first commit
Change-Id: I8a65ee5527dd16d81e87c8ac5d4bdb471e5e759d
Signed-off-by: lombardof <flombardo@cnit.it>
diff --git a/static/assets/img/OSM-logo.png b/static/assets/img/OSM-logo.png
new file mode 100644
index 0000000..7de447c
--- /dev/null
+++ b/static/assets/img/OSM-logo.png
Binary files differ
diff --git a/static/assets/img/account_circle.png b/static/assets/img/account_circle.png
new file mode 100644
index 0000000..07643f9
--- /dev/null
+++ b/static/assets/img/account_circle.png
Binary files differ
diff --git a/static/assets/img/ce.png b/static/assets/img/ce.png
new file mode 100755
index 0000000..b237a57
--- /dev/null
+++ b/static/assets/img/ce.png
Binary files differ
diff --git a/static/assets/img/cloudnode.png b/static/assets/img/cloudnode.png
new file mode 100755
index 0000000..2e748c2
--- /dev/null
+++ b/static/assets/img/cloudnode.png
Binary files differ
diff --git a/static/assets/img/controller-256.png b/static/assets/img/controller-256.png
new file mode 100755
index 0000000..34b009b
--- /dev/null
+++ b/static/assets/img/controller-256.png
Binary files differ
diff --git a/static/assets/img/cp-80.png b/static/assets/img/cp-80.png
new file mode 100755
index 0000000..3e2ad0e
--- /dev/null
+++ b/static/assets/img/cp-80.png
Binary files differ
diff --git a/static/assets/img/docker.png b/static/assets/img/docker.png
new file mode 100644
index 0000000..3e5b8b3
--- /dev/null
+++ b/static/assets/img/docker.png
Binary files differ
diff --git a/static/assets/img/employer.jpg b/static/assets/img/employer.jpg
new file mode 100755
index 0000000..c349da7
--- /dev/null
+++ b/static/assets/img/employer.jpg
Binary files differ
diff --git a/static/assets/img/employer.png b/static/assets/img/employer.png
new file mode 100644
index 0000000..5ef83a7
--- /dev/null
+++ b/static/assets/img/employer.png
Binary files differ
diff --git a/static/assets/img/euh.png b/static/assets/img/euh.png
new file mode 100755
index 0000000..f6a756e
--- /dev/null
+++ b/static/assets/img/euh.png
Binary files differ
diff --git a/static/assets/img/favicon.ico b/static/assets/img/favicon.ico
new file mode 100644
index 0000000..c588094
--- /dev/null
+++ b/static/assets/img/favicon.ico
Binary files differ
diff --git a/static/assets/img/host-256.png b/static/assets/img/host-256.png
new file mode 100755
index 0000000..df1995c
--- /dev/null
+++ b/static/assets/img/host-256.png
Binary files differ
diff --git a/static/assets/img/host.png b/static/assets/img/host.png
new file mode 100755
index 0000000..df1995c
--- /dev/null
+++ b/static/assets/img/host.png
Binary files differ
diff --git a/static/assets/img/k8s.png b/static/assets/img/k8s.png
new file mode 100644
index 0000000..922d33f
--- /dev/null
+++ b/static/assets/img/k8s.png
Binary files differ
diff --git a/static/assets/img/l2sw.png b/static/assets/img/l2sw.png
new file mode 100755
index 0000000..86bff2c
--- /dev/null
+++ b/static/assets/img/l2sw.png
Binary files differ
diff --git a/static/assets/img/ofcontroller.png b/static/assets/img/ofcontroller.png
new file mode 100755
index 0000000..34b009b
--- /dev/null
+++ b/static/assets/img/ofcontroller.png
Binary files differ
diff --git a/static/assets/img/ofl2sw.png b/static/assets/img/ofl2sw.png
new file mode 100755
index 0000000..90c62ad
--- /dev/null
+++ b/static/assets/img/ofl2sw.png
Binary files differ
diff --git a/static/assets/img/osm_logo.png b/static/assets/img/osm_logo.png
new file mode 100644
index 0000000..fbc33a3
--- /dev/null
+++ b/static/assets/img/osm_logo.png
Binary files differ
diff --git a/static/assets/img/osm_logo.svg b/static/assets/img/osm_logo.svg
new file mode 100644
index 0000000..5f5033e
--- /dev/null
+++ b/static/assets/img/osm_logo.svg
@@ -0,0 +1 @@
+<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 2674.87 967.28"><defs><style>.cls-1{fill:#397ec1;}.cls-2{fill:#e83a7a;}.cls-3{fill:#704fa0;}.cls-4{fill:#64cae1;}.cls-5{fill:#9c59a4;}</style></defs><title>osm-logo_color_rgb</title><path d="M1459.74,1460.74,1380,1636.65a36.5,36.5,0,0,1-8.55,8.55c-3.32,2.39-6.39,3.56-9.26,3.56h-4.27c-2.83,0-6-1.17-9.61-3.56a25.66,25.66,0,0,1-8.2-8.55l-79.76-175.91v381.73a21.19,21.19,0,0,1-5.35,14.59q-5.32,6.08-15.29,6.06-7.84,0-14.26-6.06a19.36,19.36,0,0,1-6.39-14.59V1368.14a19.35,19.35,0,0,1,6.39-14.58c4.29-4,9-6.06,14.26-6.06q15,0,20.64,15.67l100.42,218.63,99-218.63q5.7-15.67,19.94-15.67a20.64,20.64,0,0,1,20.64,20.64v474.33a20.64,20.64,0,0,1-20.64,20.66q-9.26,0-14.59-6.06a21.27,21.27,0,0,1-5.35-14.59Z" transform="translate(-79.91 -933.74)"/><path d="M1909.28,1836.77a11.35,11.35,0,0,0,.35,3.2,8.08,8.08,0,0,1,.36,2.5c0,1,.24,1.42.71,1.42a19.15,19.15,0,0,1-5.33,13.53q-5.34,5.7-15.32,5.7a21.38,21.38,0,0,1-12.46-4.27,17.81,17.81,0,0,1-7.49-11.4l-39.16-156.69H1705.6l-39.18,156.69a21.7,21.7,0,0,1-7.84,11.4,19.84,19.84,0,0,1-12.11,4.27q-10,0-15.31-6.41a21.7,21.7,0,0,1-5.35-14.25v-3.56L1749,1362.45q5.67-15,20.66-15c3.8,0,7.34,1.55,10.67,4.64a25.78,25.78,0,0,1,7.14,11.75v-.71Zm-89.73-186.59-51.27-214.37-52,214.37Z" transform="translate(-79.91 -933.74)"/><path d="M2042.52,1371q0-7.83,6.39-14.25t14.26-6.43q12.82,0,20.64,18.52l201.57,392.42V1371q0-7.83,6-14.25a19.33,19.33,0,0,1,14.59-6.43q7.84,0,13.88,6.43T2326,1371v474.32q0,13.53-5.7,17.1c-3.8,2.36-6.65,3.56-8.55,3.56-9.51,0-15.91-1.42-19.23-4.27s-5.46-5.46-6.4-7.84l-203-393.84v385.29c0,6.66-1.9,11.74-5.7,15.32a20.07,20.07,0,0,1-14.23,5.33,21.86,21.86,0,0,1-14.26-5.33c-4.26-3.58-6.39-8.66-6.39-15.32Z" transform="translate(-79.91 -933.74)"/><path d="M2469.9,1492.78a149.71,149.71,0,0,1,10.32-55.91,132.59,132.59,0,0,1,29.55-45.22,144.94,144.94,0,0,1,45.59-30.61q26.31-11.42,58.39-11.41a133.19,133.19,0,0,1,54.83,11.41,147.27,147.27,0,0,1,44.88,30.61,140.5,140.5,0,0,1,30.26,45.57,144.2,144.2,0,0,1,11,56.27v229.33a139.59,139.59,0,0,1-11,55.18,140.83,140.83,0,0,1-75.14,75.5,137.12,137.12,0,0,1-54.83,11,139.72,139.72,0,0,1-55.2-11,153.26,153.26,0,0,1-45.94-29.92,141.08,141.08,0,0,1-31.34-43.45,122.76,122.76,0,0,1-11.38-52.33Zm41.3,231.47a88.41,88.41,0,0,0,8.55,38.1,107.5,107.5,0,0,0,22.43,31.69,104,104,0,0,0,32.4,21.37,97.76,97.76,0,0,0,38.46,7.84,91.69,91.69,0,0,0,38.1-8.2,110.12,110.12,0,0,0,32.05-21.72,108.09,108.09,0,0,0,22.43-31.69,88.42,88.42,0,0,0,8.55-38.1V1492.78a105.74,105.74,0,0,0-7.84-41,103.12,103.12,0,0,0-21.35-32.75,97.45,97.45,0,0,0-32.07-21.73,101.49,101.49,0,0,0-39.87-7.82,97.74,97.74,0,0,0-39.89,8.17,103.39,103.39,0,0,0-54.12,55.56,101.84,101.84,0,0,0-7.84,39.53Z" transform="translate(-79.91 -933.74)"/><path d="M1369.46,1108.69q0,43.55-19.06,67.32t-53.52,23.77q-34.1,0-53.5-23.77t-19.52-66.86V1060.2q0-43.4,19.3-67.42t53.44-24q34.57,0,53.72,24.08t19.14,67.8Zm-17.74-48.8q0-36.9-14.2-55.43t-40.92-18.54q-25.81,0-40.32,18.16t-14.83,54.26v50.35q0,37.06,14.67,55.67t40.76,18.6q26.88,0,40.85-18.54t14-55.73Z" transform="translate(-79.91 -933.74)"/><path d="M1526.81,1121q0,38.58-13.44,58.66t-40.14,20.09q-29,0-43.39-23.17v84.32h-17V1029.62h15.75l.78,22.86q14.84-25.93,43.39-25.93,27,0,40.46,19.14t13.58,58.52Zm-17.13-15.67q0-32.08-10-47.2t-31.1-15.12q-27.19,0-38.77,27.62v87.91q11.59,25.14,39.08,25.14,20.68,0,30.63-15.12t10.13-46.59Z" transform="translate(-79.91 -933.74)"/><path d="M1621.79,1199.79q-29.54,0-46.17-19.31t-17-55v-20.39q0-36.76,16.07-57.67t44.16-20.93q27.19,0,41.46,17.74t14.59,54.37v16.05h-99.28v9.42q0,28.71,12.27,44.32t34.67,15.59q24.69,0,40-18.08l8.94,11.44q-16.36,22.37-49.7,22.38m-2.94-157.2q-20.25,0-31.12,14.28t-12,41.79h82v-4.5q-1.23-51.57-38.91-51.57" transform="translate(-79.91 -933.74)"/><path d="M1727.7,1029.62l.46,26.56a62.14,62.14,0,0,1,18.93-21.62,44.6,44.6,0,0,1,26.17-8q43.71,0,44.78,58.22V1196.7h-17V1086.61q-.17-22.39-7.87-33.05t-24.27-10.65q-13.42,0-24.16,10.11t-16.29,27.72v116h-17.14V1029.62Z" transform="translate(-79.91 -933.74)"/><path d="M2044,1141.42q0-18.83-10.73-29.65t-40.08-20.69q-29.32-9.88-43.09-22.08-18-15.91-18-42,0-25.79,17.74-42t45.86-16.21q28.73,0,46.95,18.84t18.22,48.48H2043q0-22.7-12.73-36.68t-34.68-14q-21.3,0-33.59,11.51t-12.27,29.73q0,17,11.59,27.8t36.9,19.22q25.33,8.43,38.29,17.46t19.15,21.23q6.17,12.21,6.19,28.71,0,26.4-17.84,42.55t-47.19,16.15a79.65,79.65,0,0,1-36-8.12,60.64,60.64,0,0,1-25.48-23.32q-9.19-15.2-9.18-35.9h17.6q0,23.79,14.36,37.37t38.75,13.58q21.32,0,34.22-11.43t12.89-30.57" transform="translate(-79.91 -933.74)"/><path d="M2091.66,1104.67q0-36.14,16.37-57.13t44.64-21q28.4,0,44.69,20.69t16.45,57V1122q0,36.76-16.45,57.3T2153,1199.79q-27.95,0-44.32-20.07t-17-55.28Zm17.3,17.21q0,28.85,11.65,45.35t32.35,16.51q21.16,0,32.34-15.89t11.37-45.51v-17.73q0-28.85-11.74-45.43t-32.26-16.59q-19.92,0-31.66,16.21t-12,44.58Z" transform="translate(-79.91 -933.74)"/><path d="M2342.89,1176.78q-14.22,23-44,23-22.7,0-34.27-15.77t-11.75-46.32v-108.1h17v107.62q0,22.7,8,34.44t23.14,11.73q32.46,0,41.54-31.5v-122.3h17.3V1196.7h-16.67Z" transform="translate(-79.91 -933.74)"/><path d="M2471.07,1045.68a64.77,64.77,0,0,0-10.81-1.08,32.3,32.3,0,0,0-23.85,9.72q-9.66,9.74-13.68,27v115.36h-17.14V1029.62h16.84l.3,25q12.2-28.11,38.31-28.1,6.79,0,10.35,2Z" transform="translate(-79.91 -933.74)"/><path d="M2551,1183.73q17.9,0,27.48-10t10.35-28.78h16.53q-1.23,25.64-16.38,40.24t-38,14.59q-29.82,0-45-19.07t-15.51-56.61v-20.37q0-38.3,15.21-57.76t45.16-19.45q24.86,0,39.22,15.69T2605.4,1086h-16.53q-.78-20.68-10.49-32t-27.5-11.37q-22.22,0-32.66,15t-10.42,46v19q0,32.08,10.49,46.66t32.73,14.58" transform="translate(-79.91 -933.74)"/><path d="M2696.82,1199.79q-29.54,0-46.17-19.31t-17-55v-20.39q0-36.76,16.07-57.67t44.16-20.93q27.19,0,41.46,17.74t14.59,54.37v16.05h-99.28v9.42q0,28.71,12.27,44.32t34.67,15.59q24.69,0,40-18.08l8.94,11.44q-16.36,22.37-49.7,22.38m-2.94-157.2q-20.25,0-31.12,14.28t-12,41.79h82v-4.5q-1.23-51.57-38.91-51.57" transform="translate(-79.91 -933.74)"/><path class="cls-1" d="M684.83,976.31c14.21,2.11,28.57,3.61,42.63,6.51,12.88,2.66,25.55,6.55,38.15,10.43,10.67,3.29,21.29,6.87,31.58,11.13a350.93,350.93,0,0,1,63.09,34,368.08,368.08,0,0,1,103.84,106.12,361.45,361.45,0,0,1,44.12,98,345.89,345.89,0,0,1,11.86,66.59,370.86,370.86,0,0,1-2.44,79.72,12.81,12.81,0,0,0,0,1.74c-4.43,26.34-11.16,52-21.24,76.82a337,337,0,0,1-41.82,74.71,331.6,331.6,0,0,1-51.4,54.69,317.32,317.32,0,0,1-61.15,41c-26.05,13.31-53.28,23.39-82.2,29a323,323,0,0,1-59.07,6.22,391.45,391.45,0,0,1-41.71-2.45,254.47,254.47,0,0,1-59.18-13.23c-15-5.3-29.81-11.48-44.43-17.86-7-3.07-13.5-7.5-20.21-11.3,7.14,1.55,13.9-.24,20.7-2.15,34.16-9.58,66.23-24,97.24-41,35.79-19.64,70-41.68,100.89-68.46,3.09-2.68,54.64-59,55.88-60.9,5.76-8.77,12.09-17.25,17-26.5,8.17-15.51,16.19-31.2,22.81-47.41,7.09-17.41,11.67-35.73,15-54.31,3.18-17.87,5.45-35.87,5.19-54-.22-15.31-1.61-30.63-3.29-45.87-2.33-21.21-7.72-41.79-14.74-61.94a325.43,325.43,0,0,0-26.8-58c-10.38-17.65-21.91-34.57-35.76-49.61a501.78,501.78,0,0,0-37.94-37.06c-10.56-9.26-22.19-17.38-33.89-25.22-10.49-7-21.73-12.95-32.64-19.36" transform="translate(-79.91 -933.74)"/><path class="cls-2" d="M213,1694.87c-12.52-12.68-25.48-24.95-37.45-38.12-15.27-16.78-28-35.52-39.37-55.13a369,369,0,0,1-42.88-113.7,374,374,0,0,1-6.85-62.6,363,363,0,0,1,8.15-86.7,346.93,346.93,0,0,1,21.75-66.81A351.38,351.38,0,0,1,183.89,1170c1.68-1.77,3.2-3.7,4.8-5.56.35-.73.68-1.44,1-2.15l0,.06a19,19,0,0,0,3.32-1.9c10.24-8.86,19.94-18.41,30.72-26.56,32.42-24.49,67.75-43.56,106.93-55.08,23.21-6.84,46.76-11.75,70.95-13.31,16-1,32-1.52,48-.22a323.28,323.28,0,0,1,63.76,11.18c20.85,6,41.33,13.17,60.09,24.41,13.61,8.17,27.75,15.62,40.63,24.82a296.3,296.3,0,0,1,79.49,84.83c9.28,14.83,16.75,30.79,25,46.24-2.88-2.26-5.48-5.22-8.74-6.66-7.34-3.25-15-6-22.59-8.5-39.13-13-79.54-19.69-120.47-22.67-25.34-1.85-50.86-1.66-76.31-1.87-8.28-.06-16.56,1.55-24.85,2.41-12,2-24.22,3.28-36,6.14-16.46,4-32.72,8.86-48.9,13.91-6.65,2.06-12.84,5.56-19.23,8.41a33,33,0,0,0-4.5,1.43A315.08,315.08,0,0,0,240.15,1345a305.23,305.23,0,0,0-38.54,67.32c-5.71,13.79-10.61,28-15,42.23a151.77,151.77,0,0,0-5.07,26.15c-2.22,17.95-4.48,35.93-5.51,54-.65,11.41.33,23,1.55,34.44,1.52,14.21,3.37,28.48,6.27,42.45a314.4,314.4,0,0,0,22.81,68.27c2.28,4.94,4.24,10,6.35,15" transform="translate(-79.91 -933.74)"/><path class="cls-3" d="M535.23,1628c6.73,3.82,13.17,8.23,20.21,11.3,14.63,6.38,29.39,12.55,44.45,17.87a254.87,254.87,0,0,0,59.18,13.22,390.9,390.9,0,0,0,41.69,2.45,323.32,323.32,0,0,0,59.09-6.22c28.9-5.56,56.13-15.64,82.18-29a316.47,316.47,0,0,0,61.16-41A332.13,332.13,0,0,0,954.59,1542a336.69,336.69,0,0,0,41.82-74.71c10.08-24.79,16.81-50.48,21.24-76.82,2,10.73,4.15,21.43,5.81,32.21a204.25,204.25,0,0,1,2.55,24.22c.55,16.35,1.33,32.77.46,49.07a316.06,316.06,0,0,1-5.79,46.62c-3.53,17.25-8.55,34.25-13.8,51.1a264.61,264.61,0,0,1-13.87,36.2c-8.8,18.24-18.06,36.31-30.31,52.62-7.38,9.81-14.45,19.85-21.91,29.6-2.85,3.72-6.38,6.92-9.54,10.42-2.88,3.17-5.43,6.71-8.58,9.58-10.24,9.29-20.66,18.39-31.07,27.5-13.15,11.49-27.83,20.82-42.69,29.92a314.83,314.83,0,0,1-89.45,37.77c-10.84,2.68-21.83,4.72-32.75,7-4.13.81-8.23,2.06-12.39,2.36-14.45,1.06-28.92,2.23-43.4,2.5a228.87,228.87,0,0,1-30.52-1.63c-13.93-1.6-28-3-41.6-6.33-18.92-4.72-37.86-10-55.92-17.29-16.57-6.65-32.54-15.32-47.77-24.72a382.22,382.22,0,0,1-43.2-31.31c-17.41-14.45-32.39-31.42-45.87-49.67-19.77-26.78-35.54-55.64-45.71-87.34-3.91-12.16-7.22-24.55-10-37a246.49,246.49,0,0,1-6.39-58.54c.36-19.07,1.87-38.15,3.42-57.17.55-6.79,2.74-13.46,4.18-20.18.92,3.77,1.12,7.91,2.91,11.19a168.31,168.31,0,0,0,12.54,19.63A532.31,532.31,0,0,0,442.88,1561c11.18,9.86,22.19,20,34.1,29,14.67,11,30.14,21.05,45.37,31.34,3.56,2.41,7.53,4.18,11.32,6.25l1.44.48Z" transform="translate(-79.91 -933.74)"/><path class="cls-4" d="M718.63,1256.77c-8.29-15.45-15.75-31.42-25-46.24a296.51,296.51,0,0,0-79.48-84.84c-12.88-9.2-27-16.64-40.65-24.8-18.76-11.24-39.22-18.39-60.09-24.41a321.77,321.77,0,0,0-63.76-11.19c-16.05-1.28-32-.81-48,.22-24.17,1.58-47.72,6.49-70.95,13.33-39.18,11.52-74.49,30.6-106.93,55.08-10.78,8.14-20.48,17.7-30.72,26.56a20.7,20.7,0,0,1-3.32,1.9c4-8.58,7.76-17.29,12.08-25.69a359,359,0,0,1,65.75-89.56A369.78,369.78,0,0,1,462.77,945a357.85,357.85,0,0,1,83.94-5c29.13,1.57,57.84,6.38,85.49,15.83,15.91,5.45,31.36,12.17,47,18.33l5.62,2.17c10.91,6.41,22.14,12.33,32.64,19.36,11.7,7.82,23.33,16,33.87,25.22a499.07,499.07,0,0,1,38,37.06c13.68,14.83,25.07,31.52,35.35,48.93a324.66,324.66,0,0,1,26.85,57.6c7.19,20.48,12.74,41.39,15.1,63,1.68,15.23,3.07,30.57,3.29,45.87.25,18.11-2,36.11-5.19,54-3.31,18.58-7.9,36.9-15,54.31-6.6,16.23-14.63,31.91-22.79,47.42-4.88,9.24-11.21,17.71-17,26.48-.62.95-5,6.73-9.53,12.52s-36.2,37.5-37,38.45c0-8.17-2.85-106.42-7.39-129.37-6-27.64-12.33-55.16-21.86-81.82-4.53-12.66-10-25-15-37.48-.21-.36-.4-.73-.6-1.09Z" transform="translate(-79.91 -933.74)"/><path class="cls-5" d="M213,1694.87s0,0,0,0l0,0Z" transform="translate(-79.91 -933.74)"/><path class="cls-5" d="M714.31,1836.73c-14.45,1.06-28.92,2.22-43.4,2.5a228.73,228.73,0,0,1-30.52-1.63c-13.95-1.6-28-3-41.61-6.33-18.92-4.72-37.86-10.05-55.92-17.29-16.57-6.66-32.53-15.32-47.76-24.73a385.72,385.72,0,0,1-43.21-31.31c-17.41-14.45-32.39-31.42-45.87-49.69-19.77-26.77-35.52-55.62-45.71-87.34-3.89-12.16-7.2-24.53-10-37a244.91,244.91,0,0,1-6.39-58.55c.35-19.07,1.85-38.13,3.42-57.16.55-6.79,2.74-13.46,4.18-20.18,1.82-8.1,3.37-16.27,5.52-24.28,7.61-28.46,18.17-55.86,30-82.82.4-.9.63-1.88.95-2.82.28-.49.62-1,.85-1.47,13.38-29.27,27.76-58,46.73-84.16,8.74-12,15.7-26,30.12-33-12,2-24.22,3.28-36,6.14-16.46,4-32.73,8.86-48.91,13.91-6.63,2.07-12.82,5.57-19.23,8.41a32.79,32.79,0,0,0-4.48,1.42A315.13,315.13,0,0,0,240.14,1345a305.1,305.1,0,0,0-38.54,67.31c-5.7,13.79-10.59,28-15,42.23a153.34,153.34,0,0,0-5.08,26.15c-2.22,17.95-4.46,35.93-5.49,54-.65,11.43.33,23,1.55,34.44,1.52,14.23,3.37,28.48,6.27,42.47a314.94,314.94,0,0,0,22.79,68.27c2.28,4.91,4.24,10,6.33,15l.87.87c6.85,11.16,13.44,22.49,20.61,33.45a336.3,336.3,0,0,0,60.83,69.51,364.88,364.88,0,0,0,191.63,86.54c21,2.75,42.12,4.05,63.3,2.69,13.77-.87,27.61-1.82,41.25-3.78,22.76-3.28,44.94-9.23,66.66-16.79,23.4-8.15,45.56-18.95,67.13-31,.63-.35,1-1.27,1.44-1.92-4.12.82-8.22,2.07-12.38,2.37" transform="translate(-79.91 -933.74)"/><path d="M1029.11,1454.42l-.22-6.08a208,208,0,0,0-2.56-24.44c-1-6.27-2.14-12.57-3.29-18.76a11.45,11.45,0,0,0-1.9-19.53,372.22,372.22,0,0,0,1.84-75.14,350.88,350.88,0,0,0-10-59.25,11.44,11.44,0,0,0-5.75-20.23,364.32,364.32,0,0,0-40.51-85.81,371.25,371.25,0,0,0-104.28-106.58,354.61,354.61,0,0,0-63.38-34.16c-9.09-3.75-19.15-7.31-31.72-11.18s-25.31-7.79-38.29-10.46c-8.42-1.74-17-3-25.45-4.13a11.46,11.46,0,0,0-20.1-3.55l-2.34-.9c-4.86-1.9-9.7-3.88-14.55-5.84-10.57-4.29-21.5-8.74-32.5-12.49a288.63,288.63,0,0,0-40.68-10.62A11.5,11.5,0,0,0,571,941.89c-7.39-.85-15-1.49-22.75-1.9a360.75,360.75,0,0,0-84.31,5A371.58,371.58,0,0,0,267.8,1047.58a362.09,362.09,0,0,0-66.05,90c-2.33,4.53-4.48,9.16-6.58,13.75a11.37,11.37,0,0,0-2.87-.41,11.53,11.53,0,0,0-8.18,19.66,354.57,354.57,0,0,0-67.73,102.1,350.32,350.32,0,0,0-21.84,67.13,366.6,366.6,0,0,0-8.2,87.06c.24,8.21.79,16.3,1.5,24.3a11.47,11.47,0,0,0,2.6,22.33c.82,5.49,1.74,10.92,2.8,16.26a372.2,372.2,0,0,0,43.05,114.16c12.82,22.11,25.77,40.24,39.57,55.42,8.33,9.15,17.25,18,25.88,26.56,1.47,1.47,2.93,2.94,4.4,4.4a11.52,11.52,0,0,0,9.4,18.2,11.68,11.68,0,0,0,4.27-.84c.14.25.3.51.46.76,4.57,7.6,9.32,15.43,14.26,23a339.33,339.33,0,0,0,61.12,69.84,365.81,365.81,0,0,0,92.85,58.93,11.3,11.3,0,0,0-.24,2.34,11.51,11.51,0,0,0,21.26,6.16,364.38,364.38,0,0,0,78.59,19.47c3.39.46,6.7.82,10,1.17,0,.06,0,.13,0,.19A11.51,11.51,0,0,0,521,1891c4.51.19,9,.33,13.31.33,5.94,0,11.73-.19,17.41-.55,14.67-.93,27.94-1.87,41.36-3.8,21.27-3.07,43.17-8.58,67-16.86,18.87-6.57,37.93-15.15,59.34-26.74a11.52,11.52,0,0,0,19.49-8.29c7.31-1.49,14.86-3,22.24-4.86A318.37,318.37,0,0,0,851,1792.34c14.34-8.78,29.46-18.35,42.93-30.11,10.23-8.93,20.82-18.17,31.06-27.48a63.77,63.77,0,0,0,5.79-6.32c1-1.14,1.92-2.3,2.91-3.4s2.25-2.37,3.39-3.55a79.91,79.91,0,0,0,6.25-7c3.64-4.76,7.17-9.59,10.7-14.42a11.49,11.49,0,0,0,13.58-18.47c11.65-16.26,20.59-34,28.1-49.59a266.9,266.9,0,0,0,14-36.42c5.07-16.27,10.26-33.76,13.83-51.24a317.87,317.87,0,0,0,5.83-46.85c.76-14.36.25-29-.24-43.1M843.61,1622.7a16.29,16.29,0,0,0-15.62,21.5q-10.64,4.87-21.2,8.8a16.43,16.43,0,0,0-30.82,8,13.62,13.62,0,0,0,.17,1.61c-5.14,1.28-10.27,2.48-15.43,3.47a321.16,321.16,0,0,1-56,6.09,16.38,16.38,0,0,0-14.4-14.59v-75.68a16.36,16.36,0,0,0,13.17-22.9,517.61,517.61,0,0,0,42.18-30.68,29.62,29.62,0,0,0,51.24-16l156.53,12.16a16.36,16.36,0,0,0,5.24,11.41c-1.52,2.17-3.06,4.32-4.62,6.43a329.86,329.86,0,0,1-51,54.33,318,318,0,0,1-46.25,32.78,16.46,16.46,0,0,0-13.19-6.68M727.34,1823.57a11.53,11.53,0,0,0-11.54,11.52c0,.27.06.52.08.78l-.46.06-4.27.32c-12.77.95-26,1.93-39,2.18-5.63.09-11.59-.1-17.87-.52-4-.27-8.06-.62-12.38-1.11l-4.61-.52c-12.19-1.36-24.79-2.79-36.72-5.76-15.72-3.93-36.26-9.42-55.62-17.19-14.72-5.9-30.23-13.95-47.42-24.55-2.58-1.6-5.18-3.31-7.77-5a16.42,16.42,0,0,0,2-7.65,16.1,16.1,0,0,0-1-5.33l183.78-88.15a16.39,16.39,0,0,0,30.17-6.66,327.86,327.86,0,0,0,56.72-6.16c5.19-1,10.35-2.2,15.51-3.5a16.43,16.43,0,0,0,8,9.26l-55.42,148.21a12.64,12.64,0,0,0-2.2-.21M226.93,1695.43a11.52,11.52,0,0,0-2-5.22L340.32,1597a16.39,16.39,0,0,0,11.54,4.73,17.21,17.21,0,0,0,2-.21c1.92,7.33,4,14.47,6.16,21.27,9.16,28.57,23,55.59,42.14,82.45a16.35,16.35,0,0,0-4.8,8.37Zm176.3-626.23c13-.86,30.2-1.65,47.72-.24,7.65.62,15,1.46,22.13,2.45,0,.17,0,.35,0,.52a16.44,16.44,0,0,0,31.9,5.65c3.15.79,6.27,1.6,9.35,2.49,18.33,5.3,39.73,12.31,59.58,24.2,3.07,1.84,6.17,3.62,9.28,5.41a16.23,16.23,0,0,0,1.35,14.86L489,1201.14a29.64,29.64,0,0,0-51.56,20,26.94,26.94,0,0,0,.14,2.79c-2.33.46-4.62.95-6.92,1.5-16.83,4.07-33.48,9.1-49,13.93a96.81,96.81,0,0,0-13,5.46,16.39,16.39,0,0,0-11.63-8l6.25-148.48A16.42,16.42,0,0,0,378.61,1072c8.39-1.31,16.57-2.23,24.61-2.75M576.64,955.47a10.84,10.84,0,0,0,7.25,1.16l67.48,192.62a16.13,16.13,0,0,0-3.59,2.39,295.09,295.09,0,0,0-31.21-25.77c-1.19-.84-2.41-1.63-3.59-2.44a16.43,16.43,0,0,0-28-17.08c-3.06-1.77-6.13-3.53-9.15-5.35-20.21-12.11-41.92-19.22-60.47-24.58-3.15-.9-6.33-1.74-9.54-2.55a15.35,15.35,0,0,0,.19-1.93,16.41,16.41,0,0,0-7-13.42Zm231.94,129.86c.9,1.27,1.8,2.53,2.69,3.85.63.9,1.25,1.88,1.88,2.82.81,1.22,1.63,2.44,2.45,3.7.7,1.08,1.39,2.2,2.09,3.31s1.52,2.36,2.26,3.59,1.5,2.48,2.25,3.74,1.38,2.25,2.06,3.4c1.58,2.68,3,5.41,4.53,8.12,1.09,2,2.23,3.91,3.28,5.89,1.27,2.41,2.41,4.86,3.61,7.3s2.37,4.67,3.48,7c.82,1.8,1.57,3.62,2.36,5.43,1.35,3.05,2.72,6.09,4,9.18.66,1.65,1.23,3.32,1.87,5,1.28,3.29,2.56,6.59,3.74,9.91a.23.23,0,0,0,0,.1,16.43,16.43,0,0,0,7.44,31.1,16,16,0,0,0,1.76-.17c.06.25.14.52.21.79.54,2.25,1,4.48,1.5,6.7.06.32.14.63.21.95.51,2.37.95,4.72,1.36,7,0,.16.06.32.09.49.43,2.41.81,4.78,1.16,7.16a1.37,1.37,0,0,0,0,.25c.35,2.45.66,4.89.93,7.3,1.49,13.57,3,29.6,3.26,45.65.19,13.61-1,28.33-3.85,45.87-.4,2.5-.84,5.06-1.3,7.69-1.38,7.74-2.91,15-4.64,22-.24,0-.47-.08-.73-.08a16.46,16.46,0,0,0-16.43,16l-67.62,8.21a16.2,16.2,0,0,0-18.92-12.33c-4.76-21.12-10.53-44-18.39-66.05-1.27-3.51-2.63-7-4-10.5a29.62,29.62,0,0,0-.08-53.76l58.31-150.61a16,16,0,0,0,4.12.59,16.3,16.3,0,0,0,8.69-2.55c.89,1.19,1.79,2.36,2.66,3.59.55.76,1.11,1.58,1.66,2.36M601.87,1656.68c-10.8-3.82-21.37-8.06-31.17-12.19a29.44,29.44,0,0,0,1.36-19.8c26.59-8.64,54-20.74,83.34-36.83,7.08-3.89,13.85-7.79,20.48-11.7a16.36,16.36,0,0,0,10.65,5.71v75.69a16.42,16.42,0,0,0-14.28,13.31c-4-.35-7.88-.7-11.7-1.09a253.22,253.22,0,0,1-58.69-13.11m86.58-107.57A16.37,16.37,0,0,0,673.78,1573c-6.55,3.85-13.23,7.71-20.21,11.54-29.14,16-56.35,28-82.74,36.57a29.66,29.66,0,0,0-52.35-4.31l-4-2.64c-11.62-7.79-23.62-15.83-35-24.34-4.24-3.18-8.39-6.59-12.49-10A16.4,16.4,0,0,0,443,1558.56a533.49,533.49,0,0,1-73-79.43c-.74-1-1.42-2.11-2.17-3.15a29.63,29.63,0,0,0-6.27-54.39c6.66-23.93,15.81-48.94,28.71-78.35a19.57,19.57,0,0,0,.74-2.11l.35-.9a13.83,13.83,0,0,0,.7-1.25c12.63-27.64,27-56.92,46.49-83.77,1.79-2.45,3.48-5,5.19-7.52,1.08-1.6,2.17-3.2,3.28-4.78a29.64,29.64,0,0,0,49.77-21.8c0-.16,0-.3,0-.46l7.2,0c21.05.11,42.82.22,64.09,1.77,44.69,3.26,83.91,10.64,119.9,22.57,1.95.65,3.78,1.27,5.54,1.88a29.68,29.68,0,0,0,36.17,40.19c1.35,3.45,2.71,6.9,3.94,10.37,7.84,21.94,13.6,44.8,18.33,65.86a16.42,16.42,0,0,0,5.45,31.45c2.11,22.54,3.69,58.88,4.56,84.35a29.63,29.63,0,0,0-18.65,46.17c-12.77,10.37-26.69,20.45-41.76,30.38a16.39,16.39,0,0,0-13.11-6.6m-275,151.66a16.28,16.28,0,0,0-8.17,2.25c-18.87-26.53-32.54-53.22-41.6-81.38-2.17-6.73-4.18-13.77-6.08-21a16.45,16.45,0,0,0-5.73-31.88c-.43,0-.82.1-1.25.13a233.48,233.48,0,0,1-3.24-42.09c.28-15.42,1.33-30.79,2.63-47.25a30.47,30.47,0,0,0,3.4.22,29.68,29.68,0,0,0,11-2.12c.87,1.25,1.69,2.55,2.6,3.77a536.24,536.24,0,0,0,73.24,79.78,16.36,16.36,0,0,0,6,25.72L415.8,1701a16.56,16.56,0,0,0-2.36-.24M291.08,1309.39a16.35,16.35,0,0,0-3.2-9.7q8.26-7.24,17-13.88A311.1,311.1,0,0,1,341,1262.37a16.4,16.4,0,0,0,29.27-14.07L373,1247a75.45,75.45,0,0,1,9.81-4c11.57-3.61,23.79-7.33,36.23-10.67q6.22-1.69,12.5-3.2c2.18-.54,4.4-1,6.62-1.44a29.66,29.66,0,0,0,6.14,12.44c-1.28,1.8-2.52,3.64-3.74,5.46-1.69,2.5-3.37,5-5.13,7.41-19.68,27.12-34.16,56.59-46.87,84.42a5.18,5.18,0,0,1-.47.81l-.74,1.8a15.6,15.6,0,0,1-.6,1.71c-13,29.66-22.24,54.89-29,79.07a28.85,28.85,0,0,0-17.24,2.56l-56.37-100.64a16.4,16.4,0,0,0,6.84-13.31m295.77-181.84a16.36,16.36,0,0,0,24-1c1.19.81,2.37,1.58,3.53,2.41a290.12,290.12,0,0,1,30.85,25.47,16.26,16.26,0,0,0-3.12,9.58,16.48,16.48,0,0,0,16.48,16.48,16.28,16.28,0,0,0,8.9-2.64,301.79,301.79,0,0,1,25.8,35.35c4.16,6.63,8,13.6,11.65,20.56a29.92,29.92,0,0,0-9.59,9.77c-1.93-.68-4-1.38-6.14-2.11-36.28-12-75.81-19.47-120.82-22.75-21.4-1.55-43.23-1.68-64.33-1.79l-7.55,0a29.49,29.49,0,0,0-5-12.76Zm222.7,328.31c-.71.92-10.1,11.3-25.29,27.89a29.5,29.5,0,0,0-16.68-5.13c-.62,0-1.2,0-1.8.08-.89-25.41-2.47-61.4-4.56-84A16.46,16.46,0,0,0,775,1378.44a.7.7,0,0,1,0-.08l67.42-8.18a16.44,16.44,0,0,0,7.3,10.54c-.22.55-.43,1.12-.65,1.66-6.81,16.72-15.29,33.13-22.7,47.2a201.76,201.76,0,0,1-12,19c-1.65,2.42-3.29,4.84-4.89,7.27M787.91,1080l-58.31,150.6a29.63,29.63,0,0,0-21.35,1.39c-3.69-7-7.55-14-11.76-20.77a306.59,306.59,0,0,0-26.09-35.73,16.37,16.37,0,0,0,3.21-18.09l109.93-80.71a16.59,16.59,0,0,0,4.37,3.31m-428.37,8.21-6.25,148.46a16.44,16.44,0,0,0-12,6.65L203.51,1165a11.63,11.63,0,0,0,.32-2.58,11.49,11.49,0,0,0-1.09-4.84c1.08-1,2.18-1.95,3.28-2.93,6.58-6,13.39-12.09,20.53-17.48,34.25-25.88,69-43.78,106.21-54.74,4.86-1.43,9.59-2.71,14.28-3.91a16.5,16.5,0,0,0,12.5,9.64M202,1168.55l137.3,78a16.21,16.21,0,0,0-.14,12.44,313.3,313.3,0,0,0-36.61,23.79c-5.94,4.48-11.71,9.21-17.32,14.14a16.4,16.4,0,0,0-23.44,22.78,330.69,330.69,0,0,0-21.54,25.69A309.26,309.26,0,0,0,208.75,1397a16.59,16.59,0,0,0-4.46-.9l-11.57-222.21a11.49,11.49,0,0,0,9.32-5.37M203.23,1429a16.46,16.46,0,0,0,9-30.3,303.62,303.62,0,0,1,31.14-51,327.42,327.42,0,0,1,21.23-25.34,16.31,16.31,0,0,0,10.05,3.51,16.5,16.5,0,0,0,6.33-1.27l56.35,100.59a29.63,29.63,0,0,0,9,53.64c-1.33,16.67-2.39,32.23-2.68,47.87a235.24,235.24,0,0,0,3.31,42.9,16.54,16.54,0,0,0-8.2,5.83l-141-81.47a16.71,16.71,0,0,0,1.36-6.54,16.45,16.45,0,0,0-12.38-15.91,118.48,118.48,0,0,1,3.43-15c3.1-10.1,6.25-19.33,9.47-28a17,17,0,0,0,3.62.43m-23.59,107.18c.25-4.35.59-8.72.95-13.07.55-6.41,1.25-12.82,2-19.19h0a16.41,16.41,0,0,0,13.19-6.68l141,81.47a16.35,16.35,0,0,0,1.2,15.32L222.18,1687.5a11.07,11.07,0,0,0-9.67-1.66c-.78-1.87-1.58-3.72-2.42-5.54a313.14,313.14,0,0,1-22.65-67.8c-3.15-15.23-5-30.58-6.24-42.25-1.36-12.79-2.15-23.49-1.55-34.1m239.84,165.78,30.38-114a15.89,15.89,0,0,0,2.88.29,16.39,16.39,0,0,0,12.13-5.4c4.07,3.43,8.18,6.81,12.43,10,11.4,8.58,23.46,16.65,35.11,24.46l4.24,2.83a29.64,29.64,0,0,0,52.3,27.76c9.92,4.18,20.67,8.5,31.66,12.38a257.4,257.4,0,0,0,59.58,13.3c3.86.4,7.85.78,11.87,1.11a16.39,16.39,0,0,0,.87,4.51l-183.77,88.14a16.38,16.38,0,0,0-25.77-2.61c-2.93-2.31-5.87-4.64-8.79-7.06a248.67,248.67,0,0,1-29.32-29,16.43,16.43,0,0,0-5.79-26.74m550.42-194.62a16.46,16.46,0,0,0-16.16,13.33l-156.52-12.17v-.19a29.56,29.56,0,0,0-9.94-22.13C800,1472.24,812,1459,812.71,1458q2.4-3.63,4.88-7.23a205.94,205.94,0,0,0,12.17-19.39c7.46-14.15,16-30.66,22.86-47.55.19-.48.36-1,.55-1.44a16.25,16.25,0,0,0,5.41,1,16.44,16.44,0,0,0,15.69-11.65l130.32,24.08c0,.06,0,.13,0,.19a11.53,11.53,0,0,0,9.24,11.3A338.72,338.72,0,0,1,976,1508.54a16.22,16.22,0,0,0-6.14-1.22m49.26-196.53a369,369,0,0,1-1.74,73.76,12.33,12.33,0,0,0-1.31-.13,11.52,11.52,0,0,0-10.81,7.61L875,1367.94c0-.36.11-.71.11-1.08a16.44,16.44,0,0,0-12-15.78c1.71-6.92,3.24-14.2,4.62-21.92,3.77-21.24,5.43-38.48,5.21-54.28-.22-16.21-1.79-32.35-3.29-46-.27-2.45-.59-4.92-.93-7.41,0-.1,0-.17,0-.25-.35-2.41-.73-4.83-1.17-7.27l-.09-.57c-.43-2.34-.87-4.7-1.38-7.07,0-.27-.11-.54-.17-.81-.49-2.3-1-4.62-1.57-7l-.19-.76a16.38,16.38,0,0,0,8.88-7.52l121.46,49.81a12.3,12.3,0,0,0-.22,2.31,11.54,11.54,0,0,0,11.52,11.54,11.33,11.33,0,0,0,3.89-.73,346.17,346.17,0,0,1,9.58,57.6M766.25,996.91c12.44,3.83,22.41,7.34,31.39,11.07a350.54,350.54,0,0,1,62.7,33.78,367.81,367.81,0,0,1,103.22,105.48,360.73,360.73,0,0,1,39.73,83.86,11.48,11.48,0,0,0-7.49,5.43L874.4,1186.72a16.29,16.29,0,0,0,.68-4.42,16.33,16.33,0,0,0-20.37-16l0-.11c-.08-.22-.14-.44-.22-.66-.93-2.64-2-5.26-3-7.87-.81-2.15-1.57-4.32-2.44-6.47-1.14-2.8-2.41-5.57-3.62-8.36-.93-2.14-1.82-4.27-2.79-6.39-1.06-2.28-2.23-4.51-3.36-6.77-1.25-2.57-2.47-5.14-3.8-7.68-1.2-2.29-2.52-4.53-3.77-6.79s-2.49-4.61-3.81-6.87c-.08-.14-.17-.27-.25-.41a1.47,1.47,0,0,0-.16-.27c-.92-1.58-1.85-3.09-2.77-4.62-.47-.77-.95-1.58-1.42-2.36-.95-1.52-1.88-3-2.82-4.45-.54-.85-1.09-1.76-1.63-2.6-.89-1.36-1.76-2.66-2.64-4l-1.77-2.66c-.82-1.22-1.66-2.37-2.49-3.55-.65-.92-1.3-1.87-1.95-2.75-.78-1.08-1.55-2.11-2.33-3.17-.13-.16-.25-.32-.36-.47a16.46,16.46,0,0,0-21.35-24.92c-1.08-1.12-2.12-2.28-3.21-3.4-9.32-9.58-19-18.79-28.87-27.45-10.84-9.51-22.76-17.81-34-25.34-5.29-3.55-10.8-6.79-16.29-10a11.4,11.4,0,0,0,.66-3.39c8,1.11,16.21,2.31,24.16,3.94,12.81,2.64,25.58,6.59,37.94,10.38m-101.05-25c4.86,2,9.72,3.94,14.59,5.86l2,.74a11.27,11.27,0,0,0-.63,3.59,11.49,11.49,0,0,0,20.5,7.19c5.43,3.13,10.86,6.33,16,9.8,11.18,7.47,23,15.67,33.67,25,10.94,9.59,21.57,19.86,31.8,30.6a16.11,16.11,0,0,0-1.82,18.82l-109.68,80.52a16.4,16.4,0,0,0-13.07-6.55,17.06,17.06,0,0,0-3.61.43L587.48,955.35A11.49,11.49,0,0,0,592.8,949a284.91,284.91,0,0,1,40.11,10.48c10.89,3.74,21.78,8.15,32.29,12.43M205.13,1139.28a358.7,358.7,0,0,1,65.36-89,367.77,367.77,0,0,1,194.1-101.53,357.5,357.5,0,0,1,83.43-5q11.49.62,22.41,1.87a11.44,11.44,0,0,0,3.15,7.55l-77.93,103.46a16.37,16.37,0,0,0-22,11c-7.23-1-14.67-1.85-22.41-2.47-8.82-.71-17.55-.87-25.71-.76s-16,.54-22.57,1c-8.12.52-16.38,1.46-24.84,2.77a16.45,16.45,0,0,0-32.2,6.71c-4.69,1.19-9.42,2.47-14.26,3.89-37.67,11.08-72.81,29.19-107.43,55.34-7.27,5.49-14.15,11.71-20.78,17.71l-2.9,2.57a12.22,12.22,0,0,0-1.92-1.58c2.07-4.53,4.19-9.1,6.47-13.53M98.25,1340.56a347.37,347.37,0,0,1,21.61-66.39A351,351,0,0,1,187,1173l.24-.28a12.24,12.24,0,0,0,1.65.65l11.62,222.9a16.4,16.4,0,0,0-4.46,31c-3.24,8.74-6.39,18-9.53,28.18a124.54,124.54,0,0,0-3.56,15.53c-.11,0-.22,0-.35,0a16.47,16.47,0,0,0-15.24,10.26l-64.49-17.95A10.25,10.25,0,0,0,103,1462a11.54,11.54,0,0,0-11.38-11.52c-.7-7.82-1.23-15.72-1.46-23.78a362.38,362.38,0,0,1,8.1-86.16m80.43,316.17c-13.63-15-26.4-32.88-39.08-54.75A368,368,0,0,1,97,1489c-1-5.18-1.93-10.45-2.74-15.78a11.57,11.57,0,0,0,7.65-6.28l64.49,18a16.73,16.73,0,0,0-.25,2.55,16.46,16.46,0,0,0,12.68,16c-1.23,10.8-2.33,21.69-2.94,32.53s.17,21.75,1.57,34.73c1.25,11.75,3.1,27.21,6.3,42.61a317.21,317.21,0,0,0,22.9,68.62c.84,1.82,1.63,3.66,2.41,5.51l-.13.11-4.21-4.15.06.11-.33-.33c-8.6-8.52-17.49-17.33-25.74-26.42m119.48,141.61a335.82,335.82,0,0,1-60.44-69c-4.91-7.5-9.62-15.32-14.18-22.87l-.49-.81a11.53,11.53,0,0,0,3.8-6.36L397,1717.4a16.46,16.46,0,0,0,13,16L399,1851a11.5,11.5,0,0,0-9,5.57,361.87,361.87,0,0,1-91.78-58.27m190.45,86A361.14,361.14,0,0,1,411,1865.13a12.08,12.08,0,0,0,.33-2.64,11.52,11.52,0,0,0-8.58-11.11l11-117.69a16.37,16.37,0,0,0,8.53-2.61,252.58,252.58,0,0,0,29.82,29.51c3,2.47,6,4.84,8.94,7.19a16.28,16.28,0,0,0-2.34,8.34,16.48,16.48,0,0,0,16.49,16.48,16.06,16.06,0,0,0,2.91-.3l26.36,86.89a11.54,11.54,0,0,0-5.68,6.38c-3.37-.36-6.76-.74-10.23-1.2m170.19-17.78c-23.55,8.2-45.22,13.66-66.26,16.68-13.28,1.92-26.45,2.85-41.06,3.77a279,279,0,0,1-30.53.24,11.52,11.52,0,0,0-11.32-9.32,11.08,11.08,0,0,0-1.46.14l-26.36-86.87a16.38,16.38,0,0,0,5.78-4.31c2.66,1.74,5.3,3.48,7.93,5.11,17.38,10.72,33.08,18.85,48,24.85,19.56,7.85,40.27,13.39,56.11,17.35,12.17,3,24.9,4.46,37.21,5.84l4.61.52c2.66.32,5.24.57,7.76.79l2.25.16c1.79.14,3.56.29,5.29.38.78,0,1.52.06,2.26.11l5,.17c.74,0,1.49,0,2.22,0s1.58,0,2.34,0c1.23,0,2.44,0,3.64,0,13.11-.25,26.37-1.23,39.21-2.18l4.26-.32c.35,0,.68-.1,1-.13.11.25.27.49.4.74-21.05,11.33-39.79,19.77-58.31,26.23m281.52-154.38a72.34,72.34,0,0,1-6,6.63c-1.17,1.2-2.34,2.41-3.47,3.66s-2,2.33-3,3.51a59.6,59.6,0,0,1-5.43,5.94c-10.21,9.28-20.78,18.5-31,27.43-13.25,11.57-28.22,21-42.41,29.71a314.28,314.28,0,0,1-88.83,37.51c-7.27,1.79-14.74,3.32-22,4.8a11.49,11.49,0,0,0-5.13-6.24l55.43-148.22a16.11,16.11,0,0,0,3.94.52A16.48,16.48,0,0,0,808.94,1661a16,16,0,0,0-.7-4.46q10.61-4,21.29-8.83a16.37,16.37,0,0,0,28.32-.33l91.46,39.1a11.33,11.33,0,0,0-.71,3.89,11.46,11.46,0,0,0,2.6,7.22c-3.59,4.91-7.19,9.81-10.87,14.64m85.22-214.88a314.37,314.37,0,0,1-5.76,46.28c-3.55,17.33-8.69,34.7-13.74,50.89a261.32,261.32,0,0,1-13.76,35.9c-7.46,15.48-16.37,33.18-27.92,49.23a11.37,11.37,0,0,0-13.17,3.5l-91.86-39.27a16.26,16.26,0,0,0,.74-4.65,16.64,16.64,0,0,0-1.35-6.54,323.18,323.18,0,0,0,46.77-33.15q3.63-3.09,7.15-6.25a333.39,333.39,0,0,0,44.48-48.71c1.58-2.12,3.12-4.29,4.65-6.47a16.23,16.23,0,0,0,8.1,2.22,16.46,16.46,0,0,0,9.48-29.93c2.07-3.64,4.08-7.31,6-11.07q7.5-14.44,13.76-29.81c1.92-4.72,3.7-9.53,5.43-14.4.25-.73.52-1.46.78-2.18q2.35-6.89,4.46-14c.32-1.06.62-2.14.93-3.21,1.31-4.61,2.56-9.29,3.72-14.09.32-1.23.59-2.52.89-3.77.79-3.45,1.57-6.95,2.28-10.49a13.24,13.24,0,0,0,1.82-.4c1.09,5.79,2.17,11.68,3.07,17.54a205.17,205.17,0,0,1,2.53,24l.21,6.09c.49,14,1,28.57.25,42.75" transform="translate(-79.91 -933.74)"/></svg>
\ No newline at end of file
diff --git a/static/assets/img/osm_small_logo.png b/static/assets/img/osm_small_logo.png
new file mode 100644
index 0000000..3bd7740
--- /dev/null
+++ b/static/assets/img/osm_small_logo.png
Binary files differ
diff --git a/static/assets/img/punto.png b/static/assets/img/punto.png
new file mode 100755
index 0000000..2e748c2
--- /dev/null
+++ b/static/assets/img/punto.png
Binary files differ
diff --git a/static/assets/img/rdcl3dlogo0.png b/static/assets/img/rdcl3dlogo0.png
new file mode 100644
index 0000000..d3ad852
--- /dev/null
+++ b/static/assets/img/rdcl3dlogo0.png
Binary files differ
diff --git a/static/assets/img/rdcl3dlogo0.svg b/static/assets/img/rdcl3dlogo0.svg
new file mode 100644
index 0000000..9cb69f5
--- /dev/null
+++ b/static/assets/img/rdcl3dlogo0.svg
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="210mm"
+ height="297mm"
+ viewBox="0 0 210 297"
+ version="1.1"
+ id="svg8"
+ inkscape:version="0.92.1 r"
+ sodipodi:docname="rdcl3dlogo0.svg">
+ <defs
+ id="defs2">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 148.5 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="210 : 148.5 : 1"
+ inkscape:persp3d-origin="105 : 99 : 1"
+ id="perspective3680" />
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath4908">
+ <path
+ d="M 0,595.28 H 841.89 V 0 H 0 Z"
+ id="path4906"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath4916">
+ <path
+ d="M 306.352,388.438 H 507.075 V 221.297 H 306.352 Z"
+ id="path4914"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ <clipPath
+ clipPathUnits="userSpaceOnUse"
+ id="clipPath4932">
+ <path
+ d="M 316.115,390.875 H 536.503 V 227.491 H 316.115 Z"
+ id="path4930"
+ inkscape:connector-curvature="0" />
+ </clipPath>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.1767767"
+ inkscape:cx="739.64715"
+ inkscape:cy="-420.11255"
+ inkscape:document-units="mm"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="1918"
+ inkscape:window-height="1057"
+ inkscape:window-x="0"
+ inkscape:window-y="21"
+ inkscape:window-maximized="1" />
+ <metadata
+ id="metadata5">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:groupmode="layer"
+ id="layer3"
+ inkscape:label="mesh">
+ <path
+ sodipodi:type="star"
+ style="fill:#ffffff;fill-opacity:1;stroke:#bbbbbb;stroke-width:17.3841629;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path4787"
+ sodipodi:sides="6"
+ sodipodi:cx="370.43555"
+ sodipodi:cy="366.59698"
+ sodipodi:r1="156.6655"
+ sodipodi:r2="67.910896"
+ sodipodi:arg1="0.80566566"
+ sodipodi:arg2="1.3292644"
+ inkscape:flatsided="true"
+ inkscape:rounded="0.08"
+ inkscape:randomized="0"
+ d="M 478.94697,479.59853 C 469.90684,488.27945 338.867,520.55992 326.82905,517.0714 314.79109,513.58288 221.31546,416.23929 218.31763,404.06986 215.3198,391.90042 252.884,262.27635 261.92413,253.59544 c 9.04012,-8.68092 140.07996,-40.96139 152.11792,-37.47287 12.03795,3.48852 105.51359,100.83211 108.51142,113.00154 2.99783,12.16944 -34.56638,141.79351 -43.6065,150.47442 z"
+ inkscape:transform-center-x="11.395173"
+ inkscape:transform-center-y="4.9400033"
+ transform="matrix(0.2835671,-1.1149783,1.1149783,0.2835671,-412.96205,855.48461)" />
+ <path
+ style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#bbbbbb;stroke-width:8.56500053;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M -54.970708,456.12241 56.534087,509.25559"
+ id="path4804"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#bbbbbb;stroke-width:8.56499958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="M 148.44237,509.46287 257.59331,457.4675"
+ id="path4821"
+ inkscape:connector-curvature="0" />
+ <path
+ style="fill:#ffff00;fill-opacity:1;fill-rule:evenodd;stroke:#bbbbbb;stroke-width:8.56499958;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ d="m 99.938633,589.32954 -0.74837,135.45219"
+ id="path4823"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ inkscape:groupmode="layer"
+ id="layer2"
+ inkscape:label="internal">
+ <path
+ sodipodi:type="star"
+ style="fill:#ffffff;fill-opacity:1;stroke:#bbbbbb;stroke-width:17.38442993;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
+ id="path4787-9"
+ sodipodi:sides="6"
+ sodipodi:cx="370.43555"
+ sodipodi:cy="366.59698"
+ sodipodi:r1="156.6655"
+ sodipodi:r2="67.910896"
+ sodipodi:arg1="0.80566566"
+ sodipodi:arg2="1.3292644"
+ inkscape:flatsided="true"
+ inkscape:rounded="0.08"
+ inkscape:randomized="0"
+ d="M 478.94697,479.59853 C 469.90684,488.27945 338.867,520.55992 326.82905,517.0714 314.79109,513.58288 221.31546,416.23929 218.31763,404.06986 215.3198,391.90042 252.884,262.27635 261.92413,253.59544 c 9.04012,-8.68092 140.07996,-40.96139 152.11792,-37.47287 12.03795,3.48852 105.51359,100.83211 108.51142,113.00154 2.99783,12.16944 -34.56638,141.79351 -43.6065,150.47442 z"
+ inkscape:transform-center-x="6.2760914"
+ inkscape:transform-center-y="2.72079"
+ transform="matrix(0.15617987,-0.6140949,0.61409515,0.15617983,-183.01537,711.09896)" />
+ </g>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot3759"
+ style="font-style:normal;font-weight:normal;font-size:122.66666412px;line-height:25px;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="scale(0.26458333)"><flowRegion
+ id="flowRegion3761"
+ style="font-size:122.66666412px"><rect
+ id="rect3763"
+ width="719.22864"
+ height="325.26913"
+ x="34.345188"
+ y="366.92557"
+ style="font-size:122.66666412px" /></flowRegion><flowPara
+ id="flowPara3765" /></flowRoot> <g
+ transform="matrix(1.8009222,0,0,-1.7503182,-655.85326,1108.8177)"
+ id="g4902">
+ <g
+ id="g4904"
+ clip-path="url(#clipPath4908)">
+ <g
+ id="g4910">
+ <g
+ id="g4912" />
+ <g
+ id="g4924">
+ <g
+ clip-path="url(#clipPath4916)"
+ id="g4922"
+ style="opacity:0.60000598">
+ <g
+ transform="translate(457.3057,235.4326)"
+ id="g4920">
+ <path
+ d="m 0,0 c 0,0 -67.64,-23.883 -88.679,-9.562 -17.311,11.784 21.144,30.998 54.706,48.909 66.833,35.666 92.133,92.846 68.499,82.501 -49.5,-21.667 -146.28,-33.667 -178.166,-20.667 -34.599,14.107 64.79,51.824 64.79,51.824 0,0 -92.79,-36.324 -62.341,-49.657 31.542,-13.813 128.717,-2.167 181.717,22.333 C 66.25,137.572 36.86,76.013 -29.973,40.347 -63.535,22.436 -101.99,5.222 -84.679,-6.562 -63.639,-20.883 0,0 0,0"
+ style="fill:#00cccc;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path4918"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g4926">
+ <g
+ id="g4928" />
+ <g
+ id="g4940">
+ <g
+ clip-path="url(#clipPath4932)"
+ id="g4938"
+ style="opacity:0.60000598">
+ <g
+ transform="translate(457.3057,235.4326)"
+ id="g4936">
+ <path
+ d="m 0,0 c 0,0 -14.54,-5.354 -35.848,-5.152 -65.958,0.625 -37.39,18.992 19.496,49.218 62.81,33.374 131.466,136.558 73.946,105.683 -25.898,-13.901 -89.028,-53.093 -178.9,-39.401 -42.667,6.5 42.456,42.657 42.456,42.657 0,0 -99.941,-37.96 -46.742,-46.242 63.642,-9.907 139.443,7.67 175.353,28.049 36.385,20.649 -14.191,-62.434 -77,-95.807 C -84.126,8.778 -98.46,-7.945 -41.361,-7.941 -14.938,-7.939 0,0 0,0"
+ style="fill:#0099ff;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path4934"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
+ </g>
+ <g
+ id="g4942"
+ transform="translate(352.8857,367.7881)">
+ <path
+ d="m 0,0 c 0,-7.147 -5.794,-12.941 -12.941,-12.941 -7.148,0 -12.942,5.794 -12.942,12.941 0,7.147 5.794,12.942 12.942,12.942 C -5.794,12.942 0,7.147 0,0"
+ style="fill:#d1d3d4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path4944"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g4946"
+ transform="translate(514.8857,367.7886)">
+ <path
+ d="m 0,0 c 0,-7.146 -5.794,-12.941 -12.941,-12.941 -7.148,0 -12.943,5.795 -12.943,12.941 0,7.147 5.795,12.942 12.943,12.942 C -5.794,12.942 0,7.147 0,0"
+ style="fill:#d1d3d4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path4948"
+ inkscape:connector-curvature="0" />
+ </g>
+ <g
+ id="g4950"
+ transform="translate(433.8857,227.4912)">
+ <path
+ d="m 0,0 c 0,-7.146 -5.794,-12.941 -12.941,-12.941 -7.148,0 -12.942,5.795 -12.942,12.941 0,7.146 5.794,12.941 12.942,12.941 C -5.794,12.941 0,7.146 0,0"
+ style="fill:#d1d3d4;fill-opacity:1;fill-rule:nonzero;stroke:none"
+ id="path4952"
+ inkscape:connector-curvature="0" />
+ </g>
+ </g>
+ </g>
+ <flowRoot
+ xml:space="preserve"
+ id="flowRoot76"
+ style="font-style:normal;font-weight:normal;font-size:40px;line-height:25px;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+ transform="matrix(0.70626936,0,0,0.48683772,-1248.224,-229.64302)"><flowRegion
+ id="flowRegion78"><rect
+ id="rect80"
+ width="1107.8884"
+ height="103.54552"
+ x="1691.3994"
+ y="2053.0723" /></flowRegion><flowPara
+ id="flowPara82"
+ style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:120.32446289px;line-height:109.19898224px;font-family:Homizio;-inkscape-font-specification:Homizio;letter-spacing:12.25505257px">RDCL3D</flowPara></flowRoot> </g>
+</svg>
diff --git a/static/assets/img/router.png b/static/assets/img/router.png
new file mode 100755
index 0000000..29444e4
--- /dev/null
+++ b/static/assets/img/router.png
Binary files differ
diff --git a/static/assets/img/server.png b/static/assets/img/server.png
new file mode 100644
index 0000000..297299d
--- /dev/null
+++ b/static/assets/img/server.png
Binary files differ
diff --git a/static/assets/img/sf_logo.png b/static/assets/img/sf_logo.png
new file mode 100644
index 0000000..3577eaa
--- /dev/null
+++ b/static/assets/img/sf_logo.png
Binary files differ
diff --git a/static/assets/img/sf_logo_big.png b/static/assets/img/sf_logo_big.png
new file mode 100644
index 0000000..3a2554a
--- /dev/null
+++ b/static/assets/img/sf_logo_big.png
Binary files differ
diff --git a/static/assets/img/sf_small_logo.png b/static/assets/img/sf_small_logo.png
new file mode 100644
index 0000000..c540257
--- /dev/null
+++ b/static/assets/img/sf_small_logo.png
Binary files differ
diff --git a/static/assets/img/switch.png b/static/assets/img/switch.png
new file mode 100755
index 0000000..86bff2c
--- /dev/null
+++ b/static/assets/img/switch.png
Binary files differ
diff --git a/static/assets/img/vl-80.png b/static/assets/img/vl-80.png
new file mode 100755
index 0000000..fde16d0
--- /dev/null
+++ b/static/assets/img/vl-80.png
Binary files differ
diff --git a/static/assets/img/vnf-100.png b/static/assets/img/vnf-100.png
new file mode 100755
index 0000000..bf893d8
--- /dev/null
+++ b/static/assets/img/vnf-100.png
Binary files differ
diff --git a/static/assets/img/vs.png b/static/assets/img/vs.png
new file mode 100755
index 0000000..86bff2c
--- /dev/null
+++ b/static/assets/img/vs.png
Binary files differ
diff --git a/static/css/rdcl.css b/static/css/rdcl.css
new file mode 100644
index 0000000..1124aaf
--- /dev/null
+++ b/static/css/rdcl.css
@@ -0,0 +1,44 @@
+.select-container-rdcl{
+
+}
+
+.select-container-rdcl-loading > .fa{
+ visibility: visible !important;
+}
+
+.select-container-rdcl-loaded > .fa{
+ visibility: hidden !important;
+}
+
+.select-container-rdcl-loading > .select-rdcl{
+ pointer-events: none !important;
+}
+
+.select-container-rdcl-loaded > .select-rdcl{
+ pointer-events: all !important;
+}
+
+.shellIframe {
+ width: 100%;
+ height: 450px;
+}
+
+/* layout.css Style */
+.upload-drop-zone {
+ height: 200px;
+ border-width: 2px;
+ margin-bottom: 20px;
+}
+
+/* skin.css Style*/
+.upload-drop-zone {
+ color: #ccc;
+ border-style: dashed;
+ border-color: #ccc;
+ line-height: 200px;
+ text-align: center
+}
+.upload-drop-zone.drop {
+ color: #222;
+ border-color: #222;
+}
\ No newline at end of file
diff --git a/static/src/adminlte_session_storage.js b/static/src/adminlte_session_storage.js
new file mode 100644
index 0000000..d18cbbe
--- /dev/null
+++ b/static/src/adminlte_session_storage.js
@@ -0,0 +1,55 @@
+/*
+ Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+function setCookie(cname, cvalue, exdays) {
+ var d = new Date();
+ d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
+ var expires = "expires=" + d.toUTCString();
+ document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
+}
+
+function getCookie(cname) {
+ var name = cname + "=";
+ var ca = document.cookie.split(';');
+ for (var i = 0; i < ca.length; i++) {
+ var c = ca[i];
+ while (c.charAt(0) == ' ') {
+ c = c.substring(1);
+ }
+ if (c.indexOf(name) == 0) {
+ return c.substring(name.length, c.length);
+ }
+ }
+ return "";
+}
+
+
+$(document).ready(function () {
+
+ //event section
+
+ // save if sidebar is collapsed or not
+ $('.sidebar-toggle').click(function (event) {
+ event.preventDefault();
+ var cookie = getCookie("collapsed_sidebar");
+ if (cookie != "") {
+ setCookie("collapsed_sidebar", "")
+ } else {
+ setCookie("collapsed_sidebar", "1")
+ }
+ });
+
+});
\ No newline at end of file
diff --git a/static/src/instancehandler/instance_list.js b/static/src/instancehandler/instance_list.js
new file mode 100644
index 0000000..161cc51
--- /dev/null
+++ b/static/src/instancehandler/instance_list.js
@@ -0,0 +1,138 @@
+/*
+ Copyright 2018 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+function performAction(url) {
+ $("#formActionNS").attr("action", url);
+ $('#modal_instance_new_action').modal('show');
+}
+
+function deleteNs(url) {
+ bootbox.confirm("Are you sure want to delete?", function (result) {
+ if (result) {
+ location.href = url
+ }
+ })
+}
+
+var addFormGroup = function (event) {
+ event.preventDefault();
+
+ var $formGroup = $(this).closest('.form-group');
+ var $formGroupClone = $formGroup.clone();
+
+ $(this)
+ .toggleClass('btn-success btn-add btn-danger btn-remove')
+ .html('–');
+
+ $formGroupClone.find('input').val('');
+ $formGroupClone.insertAfter($formGroup);
+
+};
+
+var removeFormGroup = function (event) {
+ event.preventDefault();
+ var $formGroup = $(this).closest('.form-group');
+ $formGroup.remove();
+};
+
+function showInstanceDetails(url_info) {
+ var dialog = bootbox.dialog({
+ message: '<div class="text-center"><i class="fa fa-spin fa-spinner"></i> Loading...</div>',
+ closeButton: true
+ });
+ $.ajax({
+ url: url_info,
+ type: 'GET',
+ dataType: "json",
+ contentType: "application/json;charset=utf-8",
+ success: function (result) {
+ editorJSON.setValue(JSON.stringify(result, null, "\t"));
+ editorJSON.setOption("autoRefresh", true);
+ dialog.modal('hide');
+ $('#modal_show_instance').modal('show');
+ },
+ error: function (result) {
+ dialog.modal('hide');
+ bootbox.alert("An error occurred while retrieving the information for the NS");
+ }
+ });
+}
+
+var editorJSON;
+
+$(document).ready(function () {
+ var json_editor_settings = {
+ mode: "javascript",
+ showCursorWhenSelecting: true,
+ autofocus: true,
+ lineNumbers: true,
+ lineWrapping: true,
+ foldGutter: true,
+ gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
+ autoCloseBrackets: true,
+ matchBrackets: true,
+ extraKeys: {
+ "F11": function (cm) {
+ cm.setOption("fullScreen", !cm.getOption("fullScreen"));
+ },
+ "Esc": function (cm) {
+ if (cm.getOption("fullScreen")) cm.setOption("fullScreen", false);
+ },
+ "Ctrl-Q": function (cm) {
+ cm.foldCode(cm.getCursor());
+ }
+ },
+ theme: "neat",
+ keyMap: "sublime"
+ };
+ var myJsonTextArea = document.getElementById("instance_view_json");
+ editorJSON = CodeMirror(function (elt) {
+ myJsonTextArea.parentNode.replaceChild(elt, myJsonTextArea);
+ }, json_editor_settings);
+
+
+ $(document).on('click', '.btn-add', addFormGroup);
+ $(document).on('click', '.btn-remove', removeFormGroup);
+
+ $("#formActionNS").submit(function (event) {
+ event.preventDefault(); //prevent default action
+ var post_url = $(this).attr("action"); //get form action url
+ var request_method = $(this).attr("method"); //get form GET/POST method
+ var form_data = new FormData(this); //Encode form elements for submission
+ console.log(post_url);
+ $.ajax({
+ url: post_url,
+ type: request_method,
+ data: form_data,
+ headers: {
+ "Accept": 'application/json'
+ },
+ contentType: false,
+ processData: false
+ }).done(function (response,textStatus, jqXHR) {
+ $('#modal_instance_new_action').modal('hide');
+ }).fail(function(result){
+ var data = result.responseJSON;
+ var title = "Error " + (data.code ? data.code: 'unknown');
+ var message = data.detail ? data.detail: 'No detail available.';
+ bootbox.alert({
+ title: title,
+ message: message
+ });
+ });
+ });
+
+});
\ No newline at end of file
diff --git a/static/src/projecthandler/descriptorslist.js b/static/src/projecthandler/descriptorslist.js
new file mode 100644
index 0000000..4a5975a
--- /dev/null
+++ b/static/src/projecthandler/descriptorslist.js
@@ -0,0 +1,69 @@
+
+function startFromAgent(start) {
+
+
+ if (start == 'exist'){
+ $('#div_new_agent').hide();
+ $('#div_available_agent').show();
+ }
+ else if (start == 'new'){
+ $('#div_available_agent').hide();
+ $('#div_new_agent').show();
+ }
+
+ $('.required').prop('required', function(){
+ return $(this).is(':visible');
+ });
+
+}
+/*
+function InvalidGitUrl(textbox) {
+ console.log('InvalidGitUrl', textbox,textbox.value == '' ,textbox.validity.typeMismatch)
+ if (textbox.value === '') {
+ textbox.setCustomValidity('Required git URL');
+ }
+ else if (textbox.validity.typeMismatch){
+ textbox.setCustomValidity('please enter a valid git URL');
+
+ }
+ else {
+ textbox.setCustomValidity('please enter a valid git URL');
+ }
+ return true;
+}
+*/
+function startFromRepo(start) {
+
+
+ if (start == 'exist'){
+ $('#div_new_repo').hide();
+ $('#div_available_repo').show();
+ }
+ else if (start == 'new'){
+ $('#div_available_repo').hide();
+ $('#div_new_repo').show();
+ }
+
+ $('.required').prop('required', function(){
+ return $(this).is(':visible');
+ });
+
+}
+
+$(document).ready(function () {
+ $("#startButtonsSelect :input").change(function () {
+ console.log("select")
+ startFromAgent(this.value);
+ });
+ $("#push_start_buttons_select :input").change(function () {
+ console.log("select")
+ startFromRepo(this.value);
+ });
+
+ // Bind events
+ $("form").submit(function(e) {
+ console.log("on submit form")
+ $("#start_new_deployment").button('loading');
+ });
+
+});
\ No newline at end of file
diff --git a/static/src/projecthandler/new_project.js b/static/src/projecthandler/new_project.js
new file mode 100644
index 0000000..9ca4c9e
--- /dev/null
+++ b/static/src/projecthandler/new_project.js
@@ -0,0 +1,84 @@
+/**
+ * New Project page
+ **/
+function handleTypeChoose(type) {
+ resetStartFromInputs()
+ $('#projectType').val(type);
+ $('#startGroup').show();
+ $('input[id="scratch"]').prop('checked', true);
+ $('#startButtonsSelect label').removeClass("active");
+ $('#s-scratch').addClass("active");
+ $('#createButton').prop('disabled', false);
+ //$('#projectName').val('New_'+type+'_project')
+}
+
+function startFromChoose(start) {
+ resetStartFromInputs()
+ //resetSelectors();
+ var type = $('#select_type').val();
+
+ if (start == 'files')
+ $('#div-file-upload-' + type).show();
+ else if (start == 'example')
+ //document.getElementById['#div-example-' + type].style.display = "block";
+ $('#div-example-' + type).css("display", "inline");
+
+}
+
+function resetStartFromInputs() {
+ $('div[class="start-selector"]').hide();
+ $('input[type="file"]').val('');
+ $('select[class="example-selector"]').val(null).trigger("change");
+}
+
+$(document).ready(function () {
+
+ // init selector
+ $(".start-selector").css("display", "inline");
+ $('#select_type').select2({
+ placeholder: {
+ id: '-1',
+ text: 'Select an option'
+ },
+ data: data_type_selector
+ });
+
+
+ $('#select_type').on("select2:select", function (evt) {
+ if (evt) {
+ var args = evt.params;
+ handleTypeChoose(args.data.value)
+ }
+ });
+
+ if (type_example_files) {
+ for (var key in type_example_files) {
+ $('select[id="example-' + key + '"]').select2({
+ placeholder: {
+ id: '-1',
+ text: 'Select an option'
+ },
+ data: type_example_files[key]
+ });
+ }
+
+
+ }
+
+
+
+ $("#startButtonsSelect :input").change(function () {
+ startFromChoose(this.value);
+ });
+
+
+
+ $("body").bind("ajaxSend", function (elm, xhr, s) {
+ if (s.type == "POST") {
+ xhr.setRequestHeader('csrftoken', $('#csrfmiddlewaretoken').val());
+ }
+ });
+
+ $(".start-selector").css("display", "none");
+
+});
\ No newline at end of file
diff --git a/static/src/projecthandler/osm/controller.js b/static/src/projecthandler/osm/controller.js
new file mode 100644
index 0000000..e39e332
--- /dev/null
+++ b/static/src/projecthandler/osm/controller.js
@@ -0,0 +1,107 @@
+if (typeof dreamer === 'undefined') {
+ var dreamer = {};
+}
+var level = {}
+
+dreamer.OsmController = (function(global) {
+ 'use strict';
+
+ var DEBUG = true;
+
+ OsmController.prototype.constructor = OsmController;
+
+ /**
+ * Constructor
+ */
+ function OsmController() {
+
+
+ }
+
+
+ OsmController.prototype.addNode = function(graph_editor, node, success, error) {
+ log('addNode');
+ var data_to_send = {
+ 'group_id': node.info.group[0],
+ 'element_id': node.id,
+ 'element_type': node.info.type,
+ 'element_desc_id': node.info.desc_id,
+ 'x': node.x,
+ 'y': node.y
+ };
+ new dreamer.GraphRequests().addNode(data_to_send, null, function() {
+ if (success)
+ success();
+ },error);
+ };
+
+ OsmController.prototype.addLink = function(graph_editor, link, success, error) {
+ log('addLink');
+ var data_to_send = {
+ 'desc_id': link.desc_id,
+ 'source': link.source.id,
+ 'source_type': link.source.info.type,
+ 'target': link.target.id,
+ 'target_type': link.target.info.type,
+ 'view': link.view,
+ 'group': link.group
+ };
+ new dreamer.GraphRequests().addLink(link, null, function() {
+ graph_editor._deselectAllNodes();
+
+ if (typeof old_link !== 'undefined' && old_link.length > 0 && old_link[0].index !== 'undefined') {
+ graph_editor.parent.removeLink.call(graph_editor, old_link[0].index);
+ }
+ if (success) {
+ success();
+ }
+ },error);
+ };
+
+ OsmController.prototype.removeNode = function(graph_editor, node, success, error) {
+ log('removeNode');
+ var data_to_send = {
+ 'group_id': node.info.group[0],
+ 'element_id': node.id,
+ 'element_type': node.info.type,
+ 'element_desc_id': node.info.desc_id,
+ };
+ new dreamer.GraphRequests().removeNode(data_to_send, null, function() {
+ if (success) {
+ success();
+ }
+ },error);
+ };
+
+ OsmController.prototype.removeLink = function(graph_editor, link, success, error) {
+ log('removeLink');
+ var data_to_send = {
+ 'desc_id': link.desc_id,
+ 'source': link.source.id,
+ 'source_type': link.source.info.type,
+ 'target': link.target.id,
+ 'target_type': link.target.info.type,
+ 'view': link.view,
+ 'group': link.group
+ };
+ new dreamer.GraphRequests().removeLink(data_to_send, function() {
+ if (success) {
+ success();
+ }
+ },error);
+ };
+
+ /**
+ * Log utility
+ */
+ function log(text) {
+ if (DEBUG)
+ console.log("::OsmController::", text);
+ }
+
+ return OsmController;
+}(this));
+
+if (typeof module === 'object') {
+ module.exports = dreamer.OsmController;
+}
\ No newline at end of file
diff --git a/static/src/projecthandler/osm/gui_properties.js b/static/src/projecthandler/osm/gui_properties.js
new file mode 100644
index 0000000..1af3ef4
--- /dev/null
+++ b/static/src/projecthandler/osm/gui_properties.js
@@ -0,0 +1,128 @@
+//***STEFANO
+var example_gui_properties = {
+ "v1" : {
+ "default": {
+ "shape": "cross",
+ "color": "#42f44e",
+ "label_color": "black",
+ "size": 15
+ },
+ "nodes": {
+ "ns_vl": {
+ "image" : "vl-80.png",
+ // "shape": "triangle",
+ "color": "#196B90",
+ "size": 20,
+ "name": "VL"
+ },
+ "ns_cp": {
+ "image" : "cp-80.png",
+ // "shape": "circle",
+ "color": "#F27220",
+ "size": 20,
+ "name": "CP"
+ },
+ "vnf": {
+ "image": "vnf-100.png",
+ // "shape": "square",
+ "color": "#54A698",
+ "size": 35,
+ "name": "VNF"
+ },
+ "vnf_vl": {
+ "shape": "triangle",
+ //"color": "#5FC9DB",
+ "color": "#196B90",
+ "size": 11,
+ "name": "IntVL"
+ },
+ "vnf_ext_cp": {
+ "shape": "circle",
+ //"#00CC66",
+ "color": "#F27220",
+ "size": 15,
+ "name": "ExtCP"
+ },
+ "vnf_vdu_cp": {
+ "shape": "circle",
+ //"color": "#E74C35",
+ "color": "#fce0cf",
+ "size": 15,
+ "name": "VduCP"
+ },
+ "vnf_vdu": {
+ "shape": "square",
+ //"color": "#50A7CC",
+ "color": "#54A698",
+ "size": 18,
+ "name": "VDU"
+ }
+ },
+ "graphs": null
+
+ },
+ "v0" : {
+ "default": {
+ "shape": "cross",
+ "color": "#42f44e",
+ "label_color": "black",
+ "size": 15
+ },
+ "nodes": {
+ "pippo": {
+ "image": "image.png",
+ "size": 25
+ },
+ "ns_vl": {
+ "shape": "triangle",
+ "color": "#196B90",
+ "size": 11,
+ "name": "VL"
+ },
+ "ns_cp": {
+ "shape": "circle",
+ "color": "#F27220",
+ "size": 15,
+ "name": "CP"
+ },
+ "vnf": {
+ "shape": "square",
+ "color": "#54A698",
+ "image": "router.png",
+ "size": 40,
+ "name": "VNF"
+ },
+ "vnf_vl": {
+ "shape": "triangle",
+ //"color": "#5FC9DB",
+ "color": "#196B90",
+ "size": 11,
+ "name": "IntVL"
+ },
+ "vnf_ext_cp": {
+ "shape": "circle",
+ //"#00CC66",
+ "color": "#F27220",
+ "size": 15,
+ "name": "ExtCP"
+ },
+ "vnf_vdu_cp": {
+ "shape": "circle",
+ //"color": "#E74C35",
+ "color": "#fce0cf",
+ "size": 15,
+ "name": "VduCP"
+ },
+ "vnf_vdu": {
+ "shape": "square",
+ //"color": "#50A7CC",
+ "color": "#54A698",
+ "size": 18,
+ "name": "VDU"
+ }
+ },
+ "graphs": null
+
+ },
+
+}
\ No newline at end of file
diff --git a/static/src/projecthandler/osm/project_graph.js b/static/src/projecthandler/osm/project_graph.js
new file mode 100644
index 0000000..072129f
--- /dev/null
+++ b/static/src/projecthandler/osm/project_graph.js
@@ -0,0 +1,354 @@
+//GraphEditor instance
+var graph_editor = new dreamer.ModelGraphEditor();
+var selected_vnffgId = null;
+var show_all = null;
+
+// Enable Drop Action on the Graph
+initDropOnGraph();
+
+
+
+$(document).ready(function() {
+ var descriptor_type = getUrlParameter('type') == 'ns' || getUrlParameter('type') == 'nsd' ? 'ns' : 'vnf'
+ var allowed_types = descriptor_type == 'ns' ? ['vnf', 'ns_cp', 'ns_vl'] : ['vnf_vl', 'vnf_ext_cp', 'vnf_vdu_cp', 'vnf_vdu'];
+ var params = {
+ node: {
+ type: allowed_types,
+ group: [getUrlParameter('id')]
+ },
+ link: {
+ group: [getUrlParameter('id')],
+ view: [descriptor_type]
+ }
+ }
+
+ graph_editor.addListener("refresh_graph_parameters", refreshGraphParameters);
+
+
+ // graph_editor initialization
+ graph_editor.init({
+ width: $('#graph_ed_container').width(),
+ height: $('#graph_ed_container').height(),
+ gui_properties: example_gui_properties,
+ filter_base: params,
+ behaviorsOnEvents:{
+ viewBased: false,
+ behaviors: buildBehaviorsOnEvents()
+ }
+ });
+
+ // this will filter in the different views, excluding the node types that are not listed in params
+ graph_editor.handleFiltersParams(params);
+ graph_editor.addListener("filters_changed", changeFilter);
+ graph_editor.addListener("edit_descriptor", openEditorEvent);
+
+});
+
+
+function initDropOnGraph() {
+
+ var dropZone = document.getElementById('graph_ed_container');
+ dropZone.ondrop = function(e) {
+ var group = graph_editor.getCurrentGroup()
+ e.preventDefault();
+ var nodetype = e.dataTransfer.getData("text/plain");
+ if (nodetype) {
+ var type_name = graph_editor.getTypeProperty()[nodetype].name;
+ if (nodetype == 'vnf') {
+ new dreamer.GraphRequests().getUnusedVnf(group, function(vnfs) {
+ $('#div_chose_id').hide();
+ $('#div_chose_vnf').show();
+ $('#input_choose_node_id').val(nodetype + "_" + generateUID());
+ $('#selection_chooser_vnf').empty();
+ $('#selection_chooser_vnf').append('<option >None</option>');
+ $('#modal_chooser_title_add_node').text('Add ' + type_name);
+ for (var i in vnfs) {
+ $('#selection_chooser_vnf').append('<option id="' + vnfs[i] + '">' + vnfs[i] + '</option>');
+ }
+ $('#save_choose_node_id').off('click').on('click', function() {
+ var choice = $("#selection_chooser_vnf option:selected").text();
+ var name = $('#input_choose_node_id').val();
+ if (choice == 'None') {
+ var node_information = {
+ 'id': name,
+ 'info': {
+ 'type': nodetype,
+ 'group': [group]
+ },
+ 'x': e.layerX,
+ 'y': e.layerY
+ }
+ graph_editor.addNode(node_information, function() {
+ $('#modal_choose_node_id').modal('hide');
+ }, function(error){
+ showAlert(error)
+ });
+ } else {
+ var node_information = {
+ 'existing_element': true,
+ 'id': choice,
+ 'info': {
+ 'type': nodetype,
+ 'group': [group]
+ },
+ 'x': e.layerX,
+ 'y': e.layerY
+ }
+ graph_editor.addNode(node_information, function() {
+ $('#modal_choose_node_id').modal('hide');
+ }, function(error){
+ showAlert(error)
+ });
+ }
+
+ });
+
+ $('#modal_choose_node_id').modal('show');
+ });
+
+ } else {
+ $('#div_chose_id').show();
+ $('#div_chose_vnf').hide();
+ $('#input_choose_node_id').val(nodetype + "_" + generateUID());
+ $('#modal_chooser_title_add_node').text('Add ' + type_name);
+ $('#save_choose_node_id').off('click').on('click', function() {
+ var name = $('#input_choose_node_id').val();
+ var node_information = {
+ 'id': name,
+ 'info': {
+ 'type': nodetype,
+ 'group': [group]
+ },
+ 'x': e.layerX,
+ 'y': e.layerY
+ }
+ graph_editor.addNode(node_information, function() {
+ $('#modal_choose_node_id').modal('hide');
+ }, function(error){
+ showAlert(error)
+ });
+ });
+ $('#modal_choose_node_id').modal('show');
+
+ }
+ }
+
+ }
+
+ dropZone.ondragover = function(ev) {
+ console.log("ondragover");
+ return false;
+ }
+
+ dropZone.ondragleave = function() {
+ console.log("ondragleave");
+ return false;
+ }
+}
+
+function handleForce(el) {
+ if (el.id == "topology_play") {
+ $("#topology_pause").removeClass('active');
+ $("#topology_play").addClass('active');
+ } else {
+ $("#topology_pause").addClass('active');
+ $("#topology_play").removeClass('active');
+ }
+
+ graph_editor.handleForce((el.id == "topology_play") ? true : false);
+
+}
+
+function changeFilter(e, c) {
+ var type_property = graph_editor.getTypeProperty();
+ if (c.link.view == 'ns') {
+ $("#title_header").text("NS Graph Editor")
+ $("#vnffg_options").prop("disabled", false);
+ graph_editor.refreshGraphParameters();
+ } else {
+
+ $("#title_header").text("VNF Graph Editor");
+ $("#vnffg_box").hide();
+ $("#vnffg_options").prop("disabled", true);
+ }
+
+ new dreamer.GraphRequests().getAvailableNodes({layer: c.link.view[0]}, buildPalette, showAlert);
+ updateBredCrumb(c);
+}
+
+var filters = function(e, params) {
+ graph_editor.handleFiltersParams(params);
+ $('#' + e).nextAll('li').remove();
+}
+
+function updateBredCrumb(filter_parameters){
+ var newLi = $("<li id=" + JSON.stringify(graph_editor.getCurrentGroup()) + "><a href='javascript:filters(" + JSON.stringify(graph_editor.getCurrentGroup()) + "," + JSON.stringify(filter_parameters) + ")'>" + graph_editor.getCurrentGroup() + "</a></li>");
+ $('#breadcrumb').append(newLi);
+}
+
+
+function openEditor(project_id) {
+ window.location.href = '/projects/' + project_id + '/descriptors/' + graph_editor.getCurrentView() + 'd/' + graph_editor.getCurrentGroup();
+}
+
+
+function showChooserModal(title, chooses, callback) {
+ console.log('showchooser')
+ $('#selection_chooser').empty();
+ for (var i in chooses) {
+ $('#selection_chooser').append('<option id="' + chooses[i].id + '">' + chooses[i].id + '</option>');
+ }
+ $('#modal_chooser_title').text(title)
+ var self = this;
+ $('#save_chooser').off('click').on('click', function() {
+ var choice = $("#selection_chooser option:selected").text();
+ callback(choice);
+
+ });
+ $('#modal_create_link_chooser').modal('show');
+
+}
+
+function refreshGraphParameters(e, graphParameters) {
+
+ var self = $(this);
+ if (graphParameters == null) return;
+ var vnffgIds = graphParameters.vnffgIds;
+ if (vnffgIds == null) return;
+
+ $("#selection_vnffg").empty();
+ $("#selection_vnffg").append('<option value="Global">Global</option>')
+ for (var i in vnffgIds) {
+ var vnffgId = vnffgIds[i]
+ var child = $('<option value="' + vnffgId + '">' + vnffgId + '</option>');
+ $("#selection_vnffg").append(child)
+ }
+}
+
+function changeVnffg(e) {
+ var vnffgId = e.value;
+ selected_vnffgId = vnffgId;
+ show_all_change();
+}
+
+function newVnffg() {
+ var group = graph_editor.getCurrentGroup()
+ $('#div_chose_id').show();
+ $('#div_chose_vnf').hide();
+ $('#input_choose_node_id').val("vnffg_" + generateUID());
+ $('#modal_chooser_title_add_node').text('Add VNFFG');
+ $('#save_choose_node_id').off('click').on('click', function() {
+ var name = $('#input_choose_node_id').val();
+ var node_information = {
+ 'element_id': name,
+ 'element_type': "vnffg",
+ 'group_id': group,
+ }
+ console.log(JSON.stringify(node_information))
+ new dreamer.GraphRequests().addVnffg(node_information, function(result) {
+
+ $('#modal_choose_node_id').modal('hide');
+ graph_editor.d3_graph.graph_parameters.vnffgIds.push(node_information.id)
+ refreshGraphParameters(null, graph_editor.d3_graph.graph_parameters)
+ });
+
+
+
+ });
+ $('#modal_choose_node_id').modal('show');
+}
+
+function show_all_change(e) {
+ if (!selected_vnffgId) return;
+ var vnffgId = selected_vnffgId;
+ if (e) show_all = e.checked;
+ if (show_all) {
+ handleVnffgParameter("Global", "invisible");
+ handleVnffgParameter(vnffgId, "matted");
+ } else {
+ handleVnffgParameter("Global", "matted");
+ handleVnffgParameter(vnffgId, "invisible");
+ }
+}
+
+function clickVnffg() {
+ if ($("#vnffg_box").is(':visible'))
+ $("#vnffg_box").hide();
+ else
+ $("#vnffg_box").show();
+
+}
+
+function handleVnffgParameter(vnffgId, class_name) {
+
+ if (vnffgId != "Global") {
+ selected_vnffgId = vnffgId;
+ graph_editor.setNodeClass(class_name, function(d) {
+ var result = false;
+ if (d.info.group.indexOf(vnffgId) < 0) {
+ result = true;
+ }
+ console.log(result);
+ return result;
+ });
+
+ graph_editor.setLinkClass(class_name, function(d) {
+ var result = false;
+ if (d.group.indexOf(vnffgId) < 0) {
+ result = true;
+ }
+ console.log(result);
+ return result;
+ });
+
+ } else {
+ selected_vnffgId = null;
+ graph_editor.setNodeClass(class_name, function(d) {
+ var result = false;
+ return result;
+ });
+
+ graph_editor.setLinkClass(class_name, function(d) {
+ var result = false;
+ return result;
+ });
+ }
+}
+
+function buildBehaviorsOnEvents(){
+ var contextmenuNodesAction = [
+ {
+ title: 'Show graph',
+ action: function (elm, c_node, i) {
+ if (c_node.info.type != undefined) {
+ var current_layer_nodes = Object.keys(graph_editor.model.layer[graph_editor.getCurrentView()].nodes);
+ if (current_layer_nodes.indexOf(c_node.info.type) >= 0) {
+ if (graph_editor.model.layer[graph_editor.getCurrentView()].nodes[c_node.info.type].expands) {
+ var new_layer = graph_editor.model.layer[graph_editor.getCurrentView()].nodes[c_node.info.type].expands;
+ graph_editor.handleFiltersParams({
+ node: {
+ type: Object.keys(graph_editor.model.layer[new_layer].nodes),
+ group: [c_node.id]
+ },
+ link: {
+ group: [c_node.id],
+ view: [new_layer]
+ }
+ });
+
+ }
+ else{
+ showAlert('This is not an explorable node.')
+ }
+ }
+ }
+ },
+ edit_mode: false
+ }];
+ var behavioursOnEvents = {
+ 'nodes': contextmenuNodesAction,
+
+ };
+
+ return behavioursOnEvents;
+}
\ No newline at end of file
diff --git a/static/src/utils.js b/static/src/utils.js
new file mode 100644
index 0000000..6d5e820
--- /dev/null
+++ b/static/src/utils.js
@@ -0,0 +1,153 @@
+function generateUID() {
+ return ("0000" + (Math.random() * Math.pow(36, 4) << 0).toString(36)).slice(-4)
+}
+
+function openProject(pId) {
+ window.location.href = '/projects/' + pId;
+}
+
+
+function openDescriptorView(project_id, descriptor_type, descriptor_id) {
+ console.log("openDescriptorView", project_id, descriptor_type, descriptor_id);
+ window.location.href = '/projects/' + project_id + '/descriptors/' + descriptor_type + '/' + descriptor_id;
+
+}
+
+
+function openEditorEvent(e, id) {
+ openEditor(id);
+}
+
+function nodeDragStart(event) {
+ event.dataTransfer.setData("Text", event.target.id);
+}
+
+function savePositions(el) {
+ graph_editor.savePositions();
+}
+
+function buildPalette(args) {
+ $("#paletteContainer").empty();
+ var type_property = graph_editor.getTypeProperty();
+ if (args.length > 0) {
+ args.forEach(function (category) {
+
+ var category_id = "category_" + category.category_name.replace(/[\s.*+?^${}()\/|[\]\\]/g, "_");//.replace(/\s/g, '');
+ var content_id = "palette-content-" + category.category_name.replace(/[\s.*+?^${}()\/|[\]\\]/g, "_");//.replace(/\s/g, '');
+
+ $("#paletteContainer").append('<div id="' + category_id + '" class="palette-category" ><div class="palette-header" onClick="handlePaletteCat(this);" category_id="' + category_id + '"> ' +
+ '<i class="fa fa-chevron-down "></i>' +
+ '<span> ' + category.category_name + '</span>' +
+ '</div>' +
+ '<div id="' + content_id + '" class="palette-content">' +
+
+ '</div>' +
+ '</div>');
+ category.types.forEach(function (type) {
+ console.log(graph_editor.get_name_from_d3_symbol(d3.symbolCircle))
+ var type_id = type.id.replace(/[\s.*+?^${}()|[\]\\]/g, "_");
+ var palette_node_icon;
+ if (type_property[type.id] && type_property[type.id].image && type_property[type.id].image != '') {
+ palette_node_icon = '<div class="palette-node-icon" style="background-image: url(' + (type_property[type.id].image || "") + ')"></div>';
+ }
+ else if (type_property[type.id] && type_property[type.id].shape) {
+ palette_node_icon = buildHtmlShape({
+ shape: type_property[type.id].shape,
+ color: type_property[type.id].color
+ });
+
+ }
+ else {//#1F77B4
+ palette_node_icon = '<div class="palette-node-icon"> <div class="palette-node-square" style="background:#1F77B4;"></div></div>';
+ }
+
+ var html_to_append = '<div class="palette-node ui-draggable" draggable="true" type-name="' + type.id + '" id="' + type_id + '" ondragstart="nodeDragStart(event)">' +
+ '<div class="palette-node-label">' + type.name + '</div>' +
+ '<div class="palette-node-icon-container">' +
+ palette_node_icon +
+ '</div>' +
+ '</div>'
+ $("#" + content_id).append(html_to_append);
+ });
+
+ });
+ }
+ togglePaletteSpinner(true);
+
+
+}
+
+function handlePaletteCat(item) {
+ console.log("handlePaletteContainer")
+ var category_id = $(item).attr("category_id")
+ $('#' + category_id).toggleClass("palette-close");
+
+}
+
+function togglePaletteSpinner(addOrRemove) {
+ $('#palette').toggleClass("palette-status-hidden", addOrRemove);
+}
+
+function showAlert(msg) {
+ // modal_alert_text
+ var alert_msg = ""
+ if (typeof msg == "string")
+ alert_msg = msg
+ else
+ alert_msg = JSON.stringify(msg)
+ $('#modal_alert_text').text(alert_msg);
+ $('#modal_alert').modal('show');
+}
+
+function getUrlParameter(par_name) {
+ var results = new RegExp('[\?&]' + par_name + '=([^&#]*)').exec(window.location.href);
+ if (results == null) {
+ return null;
+ } else {
+ return results[1] || 0;
+ }
+}
+
+function buildHtmlShape(args) {
+ var mySymbol = args.shape;
+ switch (mySymbol) {
+ case d3.symbolCircle:
+ return '<div class="palette-node-icon"> <div class="palette-node-circle" style="background:' + args.color + ';"></div></div>';
+ break;
+ case d3.symbolSquare:
+ return '<div class="palette-node-icon"> <div class="palette-node-square" style="background:' + args.color + ';"></div></div>';
+ break;
+ case d3.symbolDiamond:
+ return '<div class="palette-node-icon" style="background-color:' + args.color + '"></div>';
+ ;
+ break;
+ case d3.symbolTriangle:
+ return '<div class="palette-node-icon"> <div class="palette-node-triangle" style="border-color: transparent transparent ' + args.color + ' transparent;"></div></div>';
+ break;
+ case d3.symbolStar:
+ return '<div class="palette-node-icon" style="background-color:' + args.color + '"></div>';
+ ;
+ break;
+ case d3.symbolCross:
+ return '<div class="palette-node-icon" style="background-color:' + args.color + '"></div>';
+ ;
+ break;
+ default:
+ // if the string is not recognized
+ return "unknown";
+ //return d3.symbolCircleUnknown;
+ }
+
+
+}
+
+if (!String.format) {
+ String.format = function (format) {
+ var args = Array.prototype.slice.call(arguments, 1);
+ return format.replace(/{(\d+)}/g, function (match, number) {
+ return typeof args[number] != 'undefined' ?
+ args[number] :
+ match;
+ });
+ };
+}
\ No newline at end of file
diff --git a/static/topology3D/css/d3-context-menu.css b/static/topology3D/css/d3-context-menu.css
new file mode 100644
index 0000000..334513c
--- /dev/null
+++ b/static/topology3D/css/d3-context-menu.css
@@ -0,0 +1,78 @@
+.d3-context-menu {
+ position: absolute;
+ display: none;
+ background-color: #f2f2f2;
+ border-radius: 4px;
+
+ font-family: Arial, sans-serif;
+ font-size: 14px;
+ min-width: 150px;
+ border: 1px solid #d4d4d4;
+
+ z-index:1200;
+}
+
+.d3-context-menu ul {
+ list-style-type: none;
+ margin: 4px 0px;
+ padding: 0px;
+ cursor: default;
+}
+
+.d3-context-menu ul li {
+ padding: 4px 16px;
+
+ -webkit-touch-callout: none; /* iOS Safari */
+ -webkit-user-select: none; /* Chrome/Safari/Opera */
+ -khtml-user-select: none; /* Konqueror */
+ -moz-user-select: none; /* Firefox */
+ -ms-user-select: none; /* Internet Explorer/Edge */
+ user-select: none;
+}
+
+.d3-context-menu ul li:hover {
+ background-color: #4677f8;
+ color: #fefefe;
+}
+
+/*
+ Header
+*/
+
+.d3-context-menu ul li.is-header,
+.d3-context-menu ul li.is-header:hover {
+ background-color: #f2f2f2;
+ color: #444;
+ font-weight: bold;
+ font-style: italic;
+}
+
+/*
+ Disabled
+*/
+
+.d3-context-menu ul li.is-disabled,
+.d3-context-menu ul li.is-disabled:hover {
+ background-color: #f2f2f2;
+ color: #888;
+ cursor: not-allowed;
+}
+
+/*
+ Divider
+*/
+
+.d3-context-menu ul li.is-divider {
+ padding: 0px 0px;
+}
+
+.d3-context-menu ul li.is-divider:hover {
+ background-color: #f2f2f2;
+}
+
+.d3-context-menu ul hr {
+ border: 0;
+ height: 0;
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ border-bottom: 1px solid rgba(255, 255, 255, 0.3);
+}
\ No newline at end of file
diff --git a/static/topology3D/css/graph_editor_d3js.css b/static/topology3D/css/graph_editor_d3js.css
new file mode 100755
index 0000000..0433236
--- /dev/null
+++ b/static/topology3D/css/graph_editor_d3js.css
@@ -0,0 +1,415 @@
+
+.node_path {
+ opacity: 1;
+ stroke: #2F3550;
+ stroke-width: 1;
+}
+
+.node_selected {
+ opacity: 1 !important;
+ stroke: #2F3550 !important;
+ stroke-width: 3 !important;
+}
+
+.hidden_circle {
+ opacity: 0;
+ stroke: #FF0000 !important;
+ stroke-width: 2 !important;
+}
+
+.hidden_circle:hover {
+ opacity: 1;
+ stroke: #FF0000 !important;
+ stroke-width: 2;
+}
+
+.node_path:hover {
+ opacity: 1;
+ stroke: #2F3550;
+ stroke-width: 3;
+}
+
+.node_path:hover text {
+ opacity: 0.4;
+
+}
+
+.link {
+ fill: none;
+}
+
+.link path {
+ stroke-width: 2;
+}
+
+.matted {
+ opacity: 0.3;
+}
+
+.invisible {
+ visibility: hidden;
+}
+
+.drag_box {
+ padding: 0 40px 0 0;
+ margin-bottom: 0px !important;
+ padding-top: 0px;
+ top: 14px;
+ /* right: 25px !important; */
+ /* width: 15%; */
+ position: absolute;
+ z-index: 1;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ right: 0;
+ cursor: move;
+}
+
+.selector_box {
+ padding: 0 40px 0 0;
+ margin-bottom: 0px !important;
+ padding-top: 0px;
+ top: 70px;
+ /* right: 25px !important; */
+ /* width: 15%; */
+ position: absolute;
+ z-index: 1;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ right: 0;
+ cursor: move;
+}
+
+.drag_button {
+ cursor: move !important;
+ /*border-style: dashed;*/
+ border-width: thin;
+ border-color: black;
+ color: white;
+ border-radius: 50% !important;
+ height: 50px !important;
+ width: 50px !important;
+ margin-right: 5px;
+}
+
+.drag_button p {
+ font-family: "Lucida Console", Monaco, monospace;;
+ font-size: 0.6em;
+ font-weight: bold;
+ text-decoration: none;
+ color: black;
+ text-align: center;
+ padding-top: 50%;
+ padding-bottom: 50%;
+ width: 100%;
+}
+
+.left-tool-bar {
+ top: 14px;
+ cursor: default;
+ line-height: 22px;
+ position: absolute;
+
+ padding: 0px 6px;
+
+ /* top: 7px; */
+ /* right: 6px; */
+ z-index: 1;
+ text-align: center;
+ font-size: 12px;
+ /*color: #777;
+ /* border-radius: 20px; */
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.left-tool-bar-monitoring {
+
+ z-index: 1;
+ text-align: center;
+ font-size: 12px;
+
+ top: 64px;
+ cursor: default;
+ padding: 0 6px;
+ line-height: 22px;
+ position: absolute;
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.vnffg-box {
+ top: 80px;
+ left: 100px;
+ cursor: default;
+ position: absolute;
+ width: 130px;
+
+ padding-top: 0px;
+ padding-bottom: 0px;
+
+ /* top: 7px; */
+ /* right: 6px; */
+ z-index: 1;
+ text-align: center;
+ font-size: 12px;
+ /*color: #777;
+ /* border-radius: 20px; */
+
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+textarea {
+ font-family: "Lucida Console", Monaco, monospace;
+ height: 350px !important;
+ resize: none;
+}
+
+.form-group {
+ margin-bottom: 0px !important;
+ margin-top: 0px !important;
+}
+
+.modal-body {
+ overflow-y: auto;
+}
+
+[draggable=true] {
+ -khtml-user-drag: element;
+ -webkit-user-drag: element;
+ -khtml-user-select: none;
+ -webkit-user-select: none;
+}
+
+.help-key {
+ border: 1px solid #ddd;
+ padding: 4px;
+ border-radius: 3px;
+ background: #f6f6f6;
+ font-family: Courier, monospace;
+ box-shadow: #999 1px 1px 1px;
+}
+
+/*
+Palette section
+*/
+#palette {
+ position: absolute;
+ top: 20px;
+ bottom: 20px;
+ right: 22px;
+ background: #f3f3f3;
+ width: 170px;
+ text-align: center;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ border: 1px solid #bbb;
+ box-sizing: border-box;
+ padding: 0 0 0 0;
+}
+
+.palette-status-indicator {
+ top: 50%;
+ position: relative;
+ justify-content: center;
+}
+
+.palette-status-hidden > .palette-status-indicator {
+ top: 50%;
+ position: relative;
+ justify-content: center;
+ display: none;
+}
+
+.palette-container {
+ #display: none;
+ position: absolute;
+ top: 0px;
+ right: 0;
+ bottom: 25px;
+ left: 0;
+ padding: 0;
+ overflow-y: auto;
+ box-sizing: border-box;
+}
+
+.palette-category {
+
+ border-bottom: 1px solid #ccc;
+}
+
+.palette-hide {
+ display: none;
+}
+
+.palette-header {
+ position: relative;
+ background: #f3f3f3;
+ cursor: pointer;
+ text-align: left;
+ padding: 1px;
+ font-weight: bold;
+ font-size: 16px;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.palette-content {
+
+ background: #fff;
+ padding: 3px;
+}
+
+.palette-close > .palette-content {
+ background: #fff;
+ padding: 3px;
+ display: none;
+}
+
+.palette-close > .palette-header > i.fa.fa-chevron-down {
+
+ filter: none;
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";
+ -webkit-transform: rotate(-90deg);
+ -ms-transform: rotate(-90deg);
+ transform: rotate(-90deg);
+}
+
+.palette-node {
+ cursor: move;
+ margin: 3px auto;
+ height: 35px;
+ border-radius: 5px;
+ border: 1px solid #999;
+ background: #ddd no-repeat 5% 50%;
+ width: 80%;
+ background-size: contain;
+ position: relative;
+}
+
+.palette-node-label {
+ font-size: 13px;
+ font-weight: bold;
+ padding-left: 30px;
+ margin-left: auto;
+ margin-right: auto;
+ position: relative;
+ top: 50%;
+ transform: translateY(-50%);
+}
+
+.palette-node-icon-container {
+ position: absolute;
+ text-align: center;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ width: 30px;
+ border-right: 1px solid rgba(0, 0, 0, 0.1);
+ background-color: rgba(0, 0, 0, 0.05);
+}
+
+.palette-node-icon {
+ /* display: inline-block;*/
+ width: 30px;
+ height: 100%;
+ background-position: 50% 50%;
+ background-size: contain;
+ background-repeat: no-repeat;
+}
+
+.palette-node-circle {
+ display: inline-block;
+ margin-top: 2px;
+ width: 28px;
+ height: 28px;
+ -webkit-border-radius: 14px;
+ -moz-border-radius: 14px;
+ border-radius: 14px;
+ background: red;
+}
+
+.palette-node-square {
+ display: inline-block;
+ margin-top: 4px;
+ padding-top: 1px;
+ width: 26px;
+ height: 26px;
+ background: red;
+}
+
+.palette-node-triangle {
+ padding-top: 1px;
+ width: 0px;
+ height: 0px;
+ border-left: 15px solid transparent;
+ border-right: 15px solid transparent;
+ border-bottom: 30px solid #2f2f2f;
+}
+
+/*
+END Palette section
+*/
+
+/*
+Popup section
+*/
+.popup.bg {
+ fill: black;
+ opacity: 0.21;
+ border-radius: 3px;
+}
+
+.popup.summary.bg {
+ fill: white;
+ opacity: 1;
+}
+
+.popup.summary.counter {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+}
+
+.popup.summary.countervalue {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+}
+
+.popup.title {
+ fill: black;
+ font-size: 16px;
+ font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+}
+
+/*
+Popup section
+*/
\ No newline at end of file
diff --git a/static/topology3D/js/d3-context-menu.js b/static/topology3D/js/d3-context-menu.js
new file mode 100644
index 0000000..6f77042
--- /dev/null
+++ b/static/topology3D/js/d3-context-menu.js
@@ -0,0 +1,131 @@
+(function (root, factory) {
+ if (typeof module === 'object' && module.exports) {
+ module.exports = function (d3) {
+ d3.contextMenu = factory(d3);
+ return d3.contextMenu;
+ };
+ } else if (typeof define === 'function' && define.amd) {
+ try {
+ var d3 = require('d3');
+ } catch (e) {
+ d3 = root.d3;
+ }
+
+ d3.contextMenu = factory(d3);
+ define([], function () {
+ return d3.contextMenu;
+ });
+ } else if (root.d3) {
+ root.d3.contextMenu = factory(root.d3);
+ }
+}(this,
+ function (d3) {
+ return function (menu, opts) {
+ var openCallback,
+ closeCallback;
+
+ if (typeof opts === 'function') {
+ openCallback = opts;
+ } else {
+ opts = opts || {};
+ openCallback = opts.onOpen;
+ closeCallback = opts.onClose;
+ }
+
+ // create the div element that will hold the context menu
+ d3.selectAll('.d3-context-menu').data([1])
+ .enter()
+ .append('div')
+ .attr('class', 'd3-context-menu');
+
+ // close menu
+ d3.select('body').on('click.d3-context-menu', function () {
+ d3.select('.d3-context-menu').style('display', 'none');
+ if (closeCallback) {
+ closeCallback();
+ }
+ });
+
+ // this gets executed when a contextmenu event occurs
+ return function (data, index) {
+ var elm = this;
+ d3.selectAll('.d3-context-menu').html('');
+ var list = d3.selectAll('.d3-context-menu')
+ .on('contextmenu', function (d) {
+ d3.select('.d3-context-menu').style('display', 'none');
+ d3.event.preventDefault();
+ d3.event.stopPropagation();
+ })
+ .append('ul');
+ list.selectAll('li').data(typeof menu === 'function' ? menu(data) : menu).enter()
+ .filter(function (d) {
+ if(opts.type_object == 'node'){
+ if (opts.edit_mode || opts.edit_mode == d.edit_mode ) {
+ if ((d.nodes == undefined || d.nodes.length == 0) ||
+ (d.nodes != undefined && d.nodes.length > 0 && d.nodes.indexOf(data.info.type) > -1))
+ return true
+ }
+ }
+ if(opts.type_object == 'link'){
+ if (opts.edit_mode == d.edit_mode) {
+
+ return true
+ }
+ }
+ return false;
+ })
+ .append('li')
+ .attr('class', function (d) {
+ var ret = '';
+ if (d.divider) {
+ ret += ' is-divider';
+ }
+ if (d.disabled) {
+ ret += ' is-disabled';
+ }
+ if (!d.action) {
+ ret += ' is-header';
+ }
+ //if()
+ return ret;
+ })
+ .html(function (d) {
+ if (d.divider) {
+ return '<hr>';
+ }
+ if (!d.title) {
+ console.error('No title attribute set. Check the spelling of your options.');
+ }
+ return (typeof d.title === 'string') ? d.title : d.title(data);
+ })
+ .on('click', function (d, i) {
+ if (d.disabled) return; // do nothing if disabled
+ if (!d.action) return; // headers have no "action"
+ d.action(elm, data, index);
+ d3.select('.d3-context-menu').style('display', 'none');
+
+ if (closeCallback) {
+ closeCallback();
+ }
+ });
+
+ // the openCallback allows an action to fire before the menu is displayed
+ // an example usage would be closing a tooltip
+ if (openCallback) {
+ if (openCallback(data, index) === false) {
+ return;
+ }
+ }
+
+ // display context menu
+ d3.select('.d3-context-menu')
+ .style('left', (d3.event.pageX - 2) + 'px')
+ .style('top', (d3.event.pageY - 2) + 'px')
+ .style('display', 'block');
+
+ d3.event.preventDefault();
+ d3.event.stopPropagation();
+ };
+ };
+ }
+));
\ No newline at end of file
diff --git a/static/topology3D/js/event.js b/static/topology3D/js/event.js
new file mode 100755
index 0000000..cfe815c
--- /dev/null
+++ b/static/topology3D/js/event.js
@@ -0,0 +1,73 @@
+/*
+ Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+if (typeof dreamer === 'undefined') {
+ var dreamer = {};
+}
+
+dreamer.Event = (function (global) {
+ 'use strict';
+
+ function Event () {
+ this._listeners = {};
+ }
+
+ Event.prototype.addL = function (type, listener) {
+ if (typeof this._listeners[type] == "undefined"){
+ this._listeners[type] = [];
+ }
+ this._listeners[type].push(listener);
+ };
+
+ Event.prototype.fire = function (event, args) {
+ if (typeof event == "string"){
+ event = { type: event };
+ }
+ if (!event.target){
+ event.target = this;
+ }
+
+ if (!event.type){ //falsy
+ throw new Error("Event object missing 'type' property.");
+ }
+
+ if (this._listeners[event.type] instanceof Array){
+ var listeners = this._listeners[event.type];
+ for (var i=0, len=listeners.length; i < len; i++){
+ listeners[i].call(this, event, args);
+ }
+ }
+ };
+
+ Event.prototype.addListener = function (type, listener) {
+ if (this._listeners[type] instanceof Array){
+ var listeners = this._listeners[type];
+ for (var i=0, len=listeners.length; i < len; i++){
+ if (listeners[i] === listener){
+ listeners.splice(i, 1);
+ break;
+ }
+ }
+ }
+
+ };
+
+ return Event;
+}());
+
+if (typeof module === 'object') {
+ module.exports = dreamer.Event;
+}
diff --git a/static/topology3D/js/graph_editor.js b/static/topology3D/js/graph_editor.js
new file mode 100755
index 0000000..36e7c8e
--- /dev/null
+++ b/static/topology3D/js/graph_editor.js
@@ -0,0 +1,1084 @@
+/*
+ Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+if (typeof dreamer === 'undefined') {
+ var dreamer = {};
+}
+var level = {}
+
+dreamer.GraphEditor = (function (global) {
+ 'use strict';
+
+ var DEBUG = true;
+ var SHIFT_BUTTON = 16;
+ var CANC_BUTTON = 46;
+ var default_link_color = "#888";
+ var nominal_text_size = 15;
+ var nominal_stroke = 1.5;
+ var EventHandler = dreamer.Event;
+ // var IMAGE_PATH = "/static/assets/img/";
+
+
+
+ /**
+ * Constructor
+ */
+ function GraphEditor(args) {
+ log("Constructor");
+ this.eventHandler = new EventHandler();
+ this.lastKeyDown = -1;
+ this._selected_node = undefined;
+ this._selected_link = undefined;
+ this._edit_mode = true;
+ this.filter_parameters = {
+ node: {
+ type: [],
+ group: [],
+ },
+ link: {
+ group: [],
+ view: [],
+ }
+ };
+ this.current_view_id = '';
+ // graph data initailization
+ this.d3_graph = {
+ nodes: [],
+ links: [],
+ graph_parameters: {}
+
+ };
+
+
+ }
+
+
+
+ GraphEditor.prototype.init = function (args) {
+ args = args || {}
+ var self = this;
+ this.width = 550//args.width || 500;
+ this.height = 550// args.height || 500;
+ this.forceSimulationActive = false;
+
+ //FixMe
+ this.width = this.width - this.width * 0.007;
+ this.height = this.height - this.height * 0.07;
+
+ //console.log("this.width", this.width, "this.height", this.height);
+ var min_zoom = 0.1;
+ var max_zoom = 7;
+ this._setupBehaviorsOnEvents();
+ this._setupFiltersBehaviors(args);
+
+ this.type_property = {
+ "unrecognized": {
+ "shape": d3.symbolCircle,
+ "color": "white",
+ "node_label_color": "black",
+ "size": 15
+ },
+ };
+
+ this.type_property_link = {
+ "unrecognized": {
+ "color": "#888",
+ //"color": "red",
+ },
+ };
+
+ this.force = d3.forceSimulation()
+ .force("collide", d3.forceCollide().radius(40))
+ .force("link", d3.forceLink().distance(80).iterations(1).id(function (d) {
+ return d.id;
+ }))
+ .force("center", d3.forceCenter(this.width / 2, this.height / 2));
+
+ var zoom = d3.zoom().scaleExtent([min_zoom, max_zoom])
+
+ var size = d3.scalePow().exponent(2)
+ .domain([1, 100])
+ .range([8, 24]);
+
+ this.svg = d3.select("#graph_ed_container").append("svg")
+ .attr("id", "graph_svg")
+ .attr("perserveAspectRatio", "xMinYMid")
+ .attr("width", this.width)
+ .attr("height", this.height);
+
+ //End Arrow style
+ this.defs = this.svg.append("svg:defs");
+
+ this.defs.selectAll("marker")
+ .data(["unrecognized"]) // Different link/path types can be defined here
+ .enter().append("svg:marker") // This section adds in the arrows
+ .attr("id", String)
+ .attr("viewBox", "-5 -5 10 10")
+ .attr("refX", 13) //must be smarter way to calculate shift
+ .attr("refY", 0)
+ .attr("markerUnits", "userSpaceOnUse")
+ .attr("markerWidth", 12)
+ .attr("markerHeight", 12)
+ .attr("orient", "auto")
+ .append("path")
+ .attr("d", "M 0,0 m -5,-5 L 5,0 L -5,5 Z")
+ .attr('fill', this.type_property_link['unrecognized']['color']);
+
+ d3.select(window)
+ .on('keydown', function () {
+ log('keydown ' + d3.event.keyCode);
+ //d3.event.preventDefault();
+ if (self.lastKeyDown !== -1) return;
+ self.lastKeyDown = d3.event.keyCode;
+ if (self.lastKeyDown === CANC_BUTTON && self._selected_node != undefined) {
+ self.removeNode(self._selected_node, null, showAlert);
+ } else if (self.lastKeyDown === CANC_BUTTON && self._selected_link != undefined) {
+ self.removeLink(self._selected_link, null, showAlert);
+ }
+
+ })
+ .on('keyup', function () {
+ log('keyup' + self.lastKeyDown);
+ self.lastKeyDown = -1;
+ });
+ var popup = this.svg.append("g")
+ .attr("id", "popup")
+ .attr("class", "popup")
+ .attr("opacity", "0")
+ .attr("transform", "translate(1 1)")
+ .call(d3.drag()
+ .on("start", dragstarted)
+ .on("drag", dragged)
+ .on("end", dragended));
+
+ function dragstarted(d) {
+ //d3.select(this).raise().classed("active", true);
+ }
+
+ function dragged(d) {
+ //console.log(JSON.stringify(d))
+ d3.select(this).attr("transform", function () {
+ return "translate("+d3.event.x+","+d3.event.y+")";
+
+ })
+ }
+
+ function dragended(d) {
+ //d3.select(this).classed("active", false);
+ }
+
+ var chart = $("#graph_svg");
+ this.aspect = chart.width() / chart.height();
+ this.container = chart.parent();
+ $(window).on("resize", function() {
+
+ var palette_width = $("#palette").width()
+ var working_width = self.container.width() - palette_width;
+ self.width = (working_width < 0) ? 0 : working_width;
+ self.height = self.container.height();
+ chart.attr("width", self.width);
+ chart.attr("height", self.height);
+ }).trigger("resize");
+
+ }
+
+
+ GraphEditor.prototype.get_d3_symbol =
+ function (myString) {
+ log(myString)
+ switch (myString) {
+ case "circle":
+ return d3.symbolCircle;
+ break;
+ case "square":
+ return d3.symbolSquare;
+ break;
+ case "diamond":
+ return d3.symbolDiamond;
+ break;
+ case "triangle":
+ return d3.symbolTriangle;
+ break;
+ case "star":
+ return d3.symbolStar;
+ break;
+ case "cross":
+ return d3.symbolCross;
+ break;
+ default:
+ // if the string is not recognized
+ return d3.symbolCross;
+ //return d3.symbolCircleUnknown;
+ }
+
+ }
+
+ GraphEditor.prototype.get_name_from_d3_symbol =
+ function (mySymbol) {
+ //log(myString)
+ switch (mySymbol) {
+ case d3.symbolCircle:
+ return "circle";
+ break;
+ case d3.symbolSquare:
+ return "square";
+ break;
+ case d3.symbolDiamond:
+ return "diamond";
+ break;
+ case d3.symbolTriangle:
+ return "triangle";
+ break;
+ case d3.symbolStar:
+ return "star";
+ break;
+ case d3.symbolCross:
+ return "cross";
+ break;
+ default:
+ // if the string is not recognized
+ return "unknown";
+ //return d3.symbolCircleUnknown;
+ }
+
+ }
+
+ /**
+ * Start or Stop force layout
+ * @param {boolean} Required. Value true: start, false: stop
+ * @returns {boolean}
+ */
+ GraphEditor.prototype.handleForce = function (start) {
+ if (start)
+ this.force.stop();
+ this.forceSimulationActive = start;
+ this.node.each(function (d) {
+ d.fx = (start) ? null : d.x;
+ d.fy = (start) ? null : d.y;
+ });
+
+ if (start)
+ this.force.restart();
+
+ this.eventHandler.fire("force_status_changed_on", start);
+ };
+
+ /**
+ * Handle the parameters of basic filters: node type, view, group
+ * @param {Object} Required.
+ *
+ */
+ GraphEditor.prototype.handleFiltersParams = function (filtersParams, notFireEvent) {
+ console.log("handleFiltersParams", filtersParams)
+ this.filter_parameters = (filtersParams != undefined) ? filtersParams : this.filter_parameters;
+ this.current_view_id = (this.filter_parameters != undefined && this.filter_parameters.link.view[0] != undefined) ? this.filter_parameters.link.view[0] : this.current_view_id
+ this.cleanAll();
+ this.refresh();
+ this.startForce();
+ this.force.restart();
+ this._deselectAllNodes();
+ this.handleForce(this.forceSimulationActive);
+ if (!notFireEvent)
+ this.eventHandler.fire("filters_changed", filtersParams);
+
+ };
+
+ /**
+ * Add a new node to the graph.
+ * @param {Object} Required. An object that specifies tha data of the new node.
+ * @returns {boolean}
+ */
+ GraphEditor.prototype.addNode = function (args) {
+ if (args.id && args.info && args.info.type) {
+ args.fixed = true;
+ this.force.stop();
+ this.cleanAll();
+ this.d3_graph.nodes.push(args);
+ this.refresh();
+ this.startForce();
+ this.force.restart();
+ this.handleForce(this.forceSimulationActive);
+ return true;
+ }
+
+ return false;
+
+ };
+
+ /**
+ * Update the data properties of the node
+ * @param {Object} Required. An object that specifies tha data of the node.
+ * @returns {boolean}
+ */
+ GraphEditor.prototype.updateDataNode = function (args) {
+
+ };
+
+ /**
+ * Remove a node from graph and related links.
+ * @param {String} Required. Id of node to remove.
+ * @returns {boolean}
+ */
+ GraphEditor.prototype.removeNode = function (node) {
+ if (node != undefined) {
+ var node_id = node.id;
+ this.d3_graph['nodes'].forEach(function (n, index, object) {
+ if (n.id == node_id) {
+ object.splice(index, 1);
+
+ }
+
+ });
+ //TODO trovare una metodo piu efficace
+ var self = this;
+ var links_to_remove = [];
+ this.d3_graph['links'].forEach(function (l, index, object) {
+ if (node_id === l.source.id || node_id === l.target.id) {
+ links_to_remove.push(index);
+ }
+
+ });
+ var links_removed = 0;
+ links_to_remove.forEach(function (l_index) {
+ self.d3_graph['links'].splice(l_index - links_removed, 1);
+ links_removed++;
+ });
+ this.cleanAll();
+ this.refresh();
+ this.startForce();
+ this.force.restart();
+
+ return true;
+ }
+ return false;
+ };
+
+
+ /**
+ * Add a new link to graph.
+ * @param {Object} Required. An object that specifies tha data of the new Link.
+ * @returns {boolean}
+ */
+ GraphEditor.prototype.addLink = function (link) {
+ console.log(JSON.stringify(link))
+ if (link.source && link.target) {
+ this.force.stop();
+ this.cleanAll();
+ this.d3_graph.links.push(link);
+ this.refresh();
+ this.startForce();
+ this.force.restart();
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * Remove a link from graph.
+ * @param {String} Required. The identifier of link to remove.
+ * @returns {boolean}
+ */
+ GraphEditor.prototype.removeLink = function (link_id) {
+ var self = this;
+ if (link_id !== 'undefined') {
+ this.d3_graph['links'].forEach(function (l, index, object) {
+ if (link_id === l.index) {
+ object.splice(index, 1);
+
+ self.cleanAll();
+ self.refresh();
+ self.startForce();
+ self.force.restart();
+ return true;
+ }
+
+ });
+ }
+
+ return false;
+ };
+
+
+ /**
+ * Force a refresh of GraphView
+ * @returns {}
+ */
+ GraphEditor.prototype.refresh = function () {
+
+ //log(data)
+ var self = this;
+
+ this.link = this.svg
+ .selectAll()
+ .data(self.d3_graph.links
+ .filter(this.link_filter_cb)
+ )
+ .enter().append("g")
+ .attr("class", "link cleanable")
+ .append("path")
+ .attr("class", "link")
+ .attr("class", "cleanable")
+ .style("stroke-width", nominal_stroke)
+ .style("stroke", function (d) {
+ return self._link_property_by_type((d.type_link) ? d.type_link : "unrecognized", "color");
+ })
+ .attr("marker-end", function (d) {
+ if (!d.directed_edge)
+ return '';
+
+ var marker_url = (d.type_link) ? d.type_link : "unrecognized"
+ return (d.directed_edge ? "url(#" + marker_url + ")" : '');
+ });
+
+ this.nodeContainer = this.svg
+ .selectAll()
+ .data(self.d3_graph.nodes
+ .filter(this.node_filter_cb))
+ .enter()
+ .append("g")
+ // .attr("class", "nodosdads")
+ .attr("class", "node cleanable");
+
+ this.svg.selectAll('.node')
+ .data(self.d3_graph.nodes
+ .filter(this.node_filter_cb))
+
+ .filter(function (d) {
+ return (d.info.type == undefined) || (self._node_property_by_type(d.info.type, 'image', d) == undefined)
+ })
+
+ .append("svg:path")
+ .attr("d", d3.symbol()
+ .size(function (d) {
+ return Math.PI * Math.pow(self._node_property_by_type(d.info.type, 'size', d), 2) / 4;
+ })
+ .type(function (d) {
+ // console.log(d.info.type, 'shape', self.current_view_id)
+ return (self._node_property_by_type(d.info.type, 'shape', d));
+ })
+ )
+ .style("fill", function (d) {
+ return self._node_property_by_type(d.info.type, 'color', d);
+ })
+ .attr("transform", function () {
+ return "rotate(-45)";
+
+ })
+ .attr("stroke-width", 2.4)
+
+ .attr("class", "node_path")
+ .attr("id", function (d) {
+ return "path_" + d.id;
+ })
+
+ .call(d3.drag()
+ .on("start", dragstarted)
+ .on("drag", dragged)
+ .on("end", dragended));
+
+ var figure_node = this.svg.selectAll('.node')
+ .data(self.d3_graph.nodes
+ .filter(this.node_filter_cb))
+
+ .filter(function (d) {
+ return self._node_property_by_type(d.info.type, 'image', d) != undefined
+ });
+
+ figure_node.append("svg:image")
+ .attr("xlink:href", function (d) {
+ return self._node_property_by_type(d.info.type, 'image', d)
+ })
+ .attr("x", function (d) {
+ return -self._node_property_by_type(d.info.type, 'size', d) / 2
+ })
+ .attr("y", function (d) {
+ return -self._node_property_by_type(d.info.type, 'size', d) / 2
+ })
+ .attr("width", function (d) {
+ return self._node_property_by_type(d.info.type, 'size', d)
+ })
+ .attr("height", function (d) {
+ return self._node_property_by_type(d.info.type, 'size', d)
+ })
+ .style("stroke", "black")
+ .style("stroke-width", "1px")
+
+ .attr("class", "node_path")
+ .attr("id", function (d) {
+ return "path_" + d.id;
+ })
+ .call(d3.drag()
+ .on("start", dragstarted)
+ .on("drag", dragged)
+ .on("end", dragended));
+
+ figure_node.append("svg:path")
+ .attr("d", d3.symbol()
+ .size(function (d) {
+ return Math.PI * Math.pow(self._node_property_by_type(d.info.type, 'size', d) + 7, 2) / 4;
+ })
+ .type(function (d) {
+ return (self.get_d3_symbol('circle'));
+ })
+ )
+ .style("fill", 'transparent')
+ .attr("transform", function () {
+ return "rotate(-45)";
+
+ })
+ .attr("stroke-width", 2.4)
+
+ .attr("class", "hidden_circle")
+ .attr("id", function (d) {
+ return "path_" + d.id;
+ })
+
+ .call(d3.drag()
+ .on("start", dragstarted)
+ .on("drag", dragged)
+ .on("end", dragended));
+
+
+
+ this.node = this.svg.selectAll('.node')
+ .data(self.d3_graph.nodes
+ .filter(this.node_filter_cb)).selectAll("image, path, circle");
+
+
+
+ this.node.on("contextmenu", self.behavioursOnEvents.nodes["contextmenu"])
+ .on("mouseover", self.behavioursOnEvents.nodes["mouseover"])
+ .on("mouseout", self.behavioursOnEvents.nodes["mouseout"])
+ .on('click', self.behavioursOnEvents.nodes["click"])
+ .on('dblclick', self.behavioursOnEvents.nodes["dblclick"]);
+
+ this.link
+ .on("contextmenu", self.behavioursOnEvents.links["contextmenu"])
+ .on("mouseover", self.behavioursOnEvents.links["mouseover"])
+ .on('click', self.behavioursOnEvents.links["click"])
+ .on("mouseout", self.behavioursOnEvents.links["mouseout"]);
+
+
+
+ this.text = this.svg.selectAll(".node")
+ .data(self.d3_graph.nodes
+ .filter(this.node_filter_cb))
+ .append("svg:text")
+ .attr("class", "nodetext")
+ .attr("class", "cleanable")
+ .attr("dy", function(d) {
+ if (self._node_property_by_type(d.info.type, 'image', d) == undefined) {
+ //shape
+ return "-5"
+ }
+ else {
+ //image
+ return (-self._node_property_by_type(d.info.type, 'size', d)/2).toString()
+ }
+ })
+ .attr("pointer-events", "none")
+ .style("font-size", nominal_text_size + "px")
+ .style("font-family", "Lucida Console")
+ .style("fill", function (d) {
+ return self._node_property_by_type(d.info.type, 'node_label_color', d);
+ })
+ .style("text-anchor", "middle")
+ .text(function (d) {
+ return d.id;
+ });
+
+
+
+ function dragstarted(d) {
+ d.draggednode = true;
+ if (!d3.event.active) self.force.alphaTarget(0.3).restart();
+ d.fx = d.x;
+ d.fy = d.y;
+
+ }
+
+ function dragged(d) {
+ d.fx = d3.event.x;
+ d.fy = d3.event.y;
+ }
+
+ function dragended(d) {
+ d.draggednode = false;
+ if (!d3.event.active) self.force.alphaTarget(0);
+ if (self.forceSimulationActive) {
+ d.fx = null;
+ d.fy = null;
+ } else {
+ d.fx = d.x;
+ d.fy = d.y;
+ self.force.stop();
+ self.forceSimulationActive = false;
+ }
+ }
+
+
+ };
+
+ /**
+ * Start force layout on Graph.
+ *
+ */
+ GraphEditor.prototype.startForce = function () {
+ //this.force.stop();
+ var self = this
+ this.force
+ .nodes(this.d3_graph.nodes)
+ .on("tick", ticked);
+
+
+ this.force
+ .force("link")
+ .links(this.d3_graph.links);
+
+ function ticked() {
+ self.node.attr("cx", function (d) {
+ return d.x = Math.max(self._node_property_by_type(d.info.type, 'size', d), Math.min(self.width - self._node_property_by_type(d.info.type, 'size', d), d.x));
+ })
+ .attr("cy", function (d) {
+ return d.y = Math.max(self._node_property_by_type(d.info.type, 'size', d), Math.min(self.height - self._node_property_by_type(d.info.type, 'size', d), d.y));
+ });
+
+ self.link.attr("d", function (d) {
+ var dx = d.target.x - d.source.x,
+ dy = d.target.y - d.source.y,
+ dr = Math.sqrt(dx * dx + dy * dy);
+ return "M" + d.source.x + "," + d.source.y + "," + d.target.x + "," + d.target.y;
+ });
+
+ self.node.attr("transform", function (d) {
+ return "translate(" + d.x + "," + d.y + ")";
+ });
+ self.text.attr("transform", function (d) {
+ var label_pos_y = d.y + self._node_property_by_type(d.info.type, 'size', d) + 10;
+ return "translate(" + d.x + "," + label_pos_y + ")";
+ });
+ };
+
+
+
+ };
+
+ /**
+ * This method attaches an event handler.
+ * @param {String} Required. A String that specifies the name of the event.
+ * @param {Function} Required. Specifies the function to run when the event occurs.
+ * @returns {}
+ */
+ GraphEditor.prototype.addListener = function (event_name, cb) {
+ this.eventHandler.addL(event_name, cb);
+ }
+
+ /**
+ * This method removes an event handler that has been attached with the addListener() method.
+ * @param {String} Required. A String that specifies the name of the event to remove.
+ * @param {Function} Required. Specifies the function to remove.
+ * @returns {}
+ */
+ GraphEditor.prototype.removeListener = function (event_name, cb) {
+
+ }
+
+
+ GraphEditor.prototype.setNodeClass = function (class_name, filter_cb) {
+ log("setNodeClass");
+ var self = this;
+ this.svg.selectAll('.node').classed(class_name, false);
+ this.svg.selectAll('.node')
+ .classed(class_name, filter_cb);
+ }
+
+ GraphEditor.prototype.setLinkClass = function (class_name, filter_cb) {
+ log("setLinkClass");
+ var self = this;
+ this.svg.selectAll('.link').classed(class_name, false);
+ this.svg.selectAll('.link')
+ .classed(class_name, filter_cb);
+ }
+
+ GraphEditor.prototype.showNodeInfo = function(args){
+ this.addLinesToPopup(args['node_info'], "Info about node selected")
+ this.handlePopupVisibility(true, 'right')
+ }
+ GraphEditor.prototype.addLinesToPopup = function(data, title) {
+ var self = this;
+ var index = 1;
+ var translate_y = 0;
+ var width_popup = 400;
+ var height_popup = 0;
+
+ d3.selectAll(".popupcleanable").remove(); // clean
+
+ var popupbg = d3.select(".popup").append("rect")
+ .attr("id", "popupbg")
+ .attr("class", "popup bg popupcleanable cleanable")
+ .attr("width", "400")
+ .attr("height", "0")
+ .attr("rx", 10) // set the x corner curve radius
+ .attr("ry", 10); // set the y corner curve radius
+
+
+ d3.select(".popup").append("svg:path")
+ .attr("d", d3.symbol()
+ .size(function (d) {
+ return 80
+ })
+ .type(function (d) {
+ return (self.get_d3_symbol());
+ })
+ )
+ .style("fill", 'red')
+ .attr("transform", function () {
+ return "translate(380,15) rotate(-45)";
+
+ })
+ .attr("stroke-width", 2.4)
+ .attr("id", "close_popup")
+ .attr("class", "popupcleanable cleanable")
+ .on("click", function(d) {
+ self.handlePopupVisibility(false);
+ });
+
+ d3.select(".popup").append("text")
+ .attr("class", "popup title popupcleanable cleanable")
+ .attr("x", "10")
+ .attr("y", "20")
+ .text(title);
+
+ for (var i in data) {
+ //console.log(i, data, data[i])
+ //var typeofvalue = typeof data[i];
+ var record = data[i];
+ index = this._addRecordToPopup(i, record,index)
+
+ }
+
+ };
+
+ GraphEditor.prototype._addRecordToPopup = function (key, record, index, tab) {
+ //console.log("_addRecordToPopup", key, record, index)
+ var translate_y = 23 * index;
+ var summary = d3.select(".popup").append("g")
+ .attr("class", "popup summary d popupcleanable cleanable")
+ .attr("transform", "translate(10 " + translate_y + ")");
+ if(Object.prototype.toString.call( record ) !== '[object Array]'){ //is a record simple key:value
+ //console.log(key, record)
+ var summary_g = summary.append("g");
+ summary_g.append("rect")
+ .attr("class", "popup summary bg popupcleanable cleanable")
+ .attr("width", "380")
+ .attr("height", "20");
+
+ summary_g.append("text")
+ .attr("class", "popup summary popupcleanable cleanable")
+ .attr("x", (tab)? tab: 10)
+ .attr("y", "17")
+ .attr("width", "100")
+ .text(function(d){
+ return key.toUpperCase() + ":";
+ });
+
+ summary_g.append("text")
+ .attr("class", "popup summary popupcleanable cleanable")
+ .attr("x", "370")
+ .attr("y", "17")
+ .attr("text-anchor", "end")
+ .text(function(d){return record});
+ }
+ else {//is a record simple complex: have a list of sub record key:value
+ //index ++;
+ this._addRecordToPopup(key, "", index)
+ for(var r in record){
+ //console.log(i, r, record, record[r])
+ for(var k in record[r]){
+ //console.log(i, r, k, record[r][k])
+ var curr_key = k;
+ var recordValue = record[r][k]
+
+ index ++;
+ this._addRecordToPopup(curr_key, recordValue, index, 20)
+ }
+ }
+
+ }
+
+ translate_y = 30 * index++;
+ d3.select('#popupbg').attr("height", translate_y);
+ return index;
+ };
+
+
+
+ /**
+ * Remove all the graph objects from the view
+ */
+ GraphEditor.prototype.cleanAll = function () {
+ this.svg.selectAll('.cleanable').remove();
+ };
+
+ /**
+ * Internal functions
+ */
+
+ GraphEditor.prototype._node_property_by_type = function (type, property, node) {
+ //console.log(type, property, layer, group)
+ var unrecognized = function (ui_prop, property) {
+ return ui_prop['unrecognized'][property]
+ };
+
+ //type recognized
+ if (this.type_property[type]) {
+
+ if (this.type_property[type]['property']) {
+ var filt_property = this.type_property[type]['property']
+ return this.type_property[type][node.info[filt_property]][property]
+ } else { // type without property spec
+
+ return this.type_property[type][property]
+
+ }
+
+ } else { //type unrecognized
+ return unrecognized(this.type_property, property)
+ }
+
+ };
+
+ GraphEditor.prototype._link_property_by_type = function (type, property) {
+ //log(type + "-" + property)
+ if (this.type_property_link[type] != undefined && this.type_property_link[type][property] != undefined) {
+ //if(property == "shape")
+ // log("dentro" + this.type_property[type][property])
+ return this.type_property_link[type][property];
+ } else {
+ return this.type_property_link['unrecognized'][property];
+ }
+
+ }
+
+
+ /**
+ *
+ *
+ *
+ */
+ GraphEditor.prototype._setupFiltersBehaviors = function (args) {
+
+ var self = this;
+
+ this.node_filter_cb = args.node_filter_cb || function (d) {
+
+ var cond_view = true,
+ cond_group = true;
+ //log(d.info.type + " " + self.filter_parameters.node.type + " group: " + self.filter_parameters.node.group + "- " + d.info.group)
+ // check filter by node type
+ if (self.filter_parameters.node.type.length > 0) {
+
+ if (self.filter_parameters.node.type.indexOf(d.info.type) < 0)
+ cond_view = false;
+ }
+
+ // check filter by group
+ if (self.filter_parameters.node.group.length > 0) {
+ self.filter_parameters.node.group.forEach(function (group) {
+ if (d.info.group.indexOf(group) < 0)
+ cond_group = false;
+ });
+
+
+ }
+
+
+ return cond_view && cond_group;
+ };
+
+ this.link_filter_cb = args.link_filter_cb || function (d) {
+ var cond_view = true,
+ cond_group = true;
+
+ // check filter by view
+ if (self.filter_parameters.link.view.length > 0) {
+ self.filter_parameters.link.view.forEach(function (view) {
+ if (d.view.indexOf(view) < 0)
+ cond_view = false;
+ });
+ }
+
+ // check filter by group
+ if (self.filter_parameters.link.group.length > 0) {
+ self.filter_parameters.link.group.forEach(function (group) {
+ if (d.group.indexOf(group) < 0)
+ cond_group = false;
+ });
+ }
+ return cond_view && cond_group;
+ };
+
+ };
+
+ /**
+ *
+ *
+ */
+ GraphEditor.prototype._setupBehaviorsOnEvents = function () {
+ log("_setupBehaviorsOnEvents");
+ var self = this;
+ this.behavioursOnEvents = {
+ 'nodes': {
+ 'click': function (d) {
+ d3.event.preventDefault();
+ log('click', d);
+ if (self.lastKeyDown == SHIFT_BUTTON && self._selected_node != undefined) {
+ var source_id = self._selected_node.id;
+ var target_id = d.id;
+ log(JSON.stringify(self.filter_parameters.link.view));
+ var new_link = {
+ source: source_id,
+ target: target_id,
+ view: self.filter_parameters.link.view[0],
+ group: self.filter_parameters.link.group[0],
+ };
+ self.addLink(new_link);
+ self._deselectAllNodes();
+ } else {
+ self._selectNodeExclusive(this, d);
+ }
+
+ },
+ 'mouseover': function (d) {
+
+ },
+ 'mouseout': function (d) {},
+ 'dblclick': function (d) {
+ d3.event.preventDefault();
+ log('dblclick');
+ },
+ 'contextmenu': function (d, i) {
+ d3.event.preventDefault();
+ log("contextmenu node");
+ self.eventHandler.fire("right_click_node", d);
+ }
+ },
+ 'links': {
+ 'click': function (event) {
+
+ },
+ 'dblclick': function (event) {
+
+ }
+ }
+ };
+ };
+
+ /**
+ * Deselect previously selected nodes
+ *
+ */
+ GraphEditor.prototype._deselectAllNodes = function () {
+ log("_deselectAllNodes");
+ this.node.classed("node_selected", false);
+ this._selected_node = undefined;
+ };
+
+ GraphEditor.prototype._deselectAllLinks = function () {
+ log("_deselectAllLinks");
+ this.link.classed("link_selected", false).style('stroke-width', 2);
+ this._selected_link = undefined;
+ };
+ /**
+ * Select node in exclusive mode
+ * @param {Object} Required. Element selected on click event
+ */
+ GraphEditor.prototype._selectNodeExclusive = function (node_instance, node_id) {
+ log("_selectNodeExclusive ");
+ var activeClass = "node_selected";
+ var alreadyIsActive = d3.select(node_instance).classed(activeClass);
+ this._deselectAllNodes();
+ this._deselectAllLinks();
+ d3.select(node_instance).classed(activeClass, !alreadyIsActive);
+ this._selected_node = (alreadyIsActive) ? undefined : node_instance.__data__;
+ };
+
+ /**
+ * Select node in exclusive mode
+ * @param {Object} Required. Element selected on click event
+ */
+ GraphEditor.prototype._selectLinkExclusive = function (link_instance, link_id) {
+ log("_selectLinkExclusive ");
+ var activeClass = "link_selected";
+ var alreadyIsActive = d3.select(link_instance).classed(activeClass);
+ this._deselectAllNodes();
+ this._deselectAllLinks();
+ d3.select(link_instance).classed(activeClass, !alreadyIsActive);
+ d3.select(link_instance).style('stroke-width', 4)
+ this._selected_link = link_instance.__data__;
+ };
+
+ /**
+ * Callback to resize SVG element on window resize
+ */
+ GraphEditor.prototype.resizeSvg = function (width, height) {
+ log("resizeSvg");
+ log(event);
+ this.width = width || this.width;
+ this.height = height || this.height;
+ this.svg.attr('width', width);
+ this.svg.attr('height', height);
+
+ }
+
+ GraphEditor.prototype.handlePopupVisibility = function(visible, side) {
+ var opacity = (visible) ? 1 : 0;
+
+ var translate_op = (side == "left") ? "translate(50 50)" : "translate("+(this.width - 450).toString()+" 50)";
+
+ if (!visible) {
+ d3.selectAll(".popupcleanable").remove();
+ d3.select(".popup")
+ .attr("transform", "translate(-1 -1)");
+ } else {
+ d3.select(".popup")
+ .attr("transform", translate_op);
+ }
+ d3.select(".popup").attr("opacity", opacity);
+ };
+
+ GraphEditor.prototype.refreshGraphParameters = function (graphParameters) {
+ this.eventHandler.fire("refresh_graph_parameters", graphParameters);
+ }
+
+ /**
+ * Log utility
+ */
+ function log(text) {
+ if (DEBUG)
+ console.log("::GraphEditor::", text);
+ }
+
+
+
+ return GraphEditor;
+
+
+}(this));
+
+if (typeof module === 'object') {
+ module.exports = dreamer.GraphEditor;
+}
\ No newline at end of file
diff --git a/static/topology3D/js/graph_request.js b/static/topology3D/js/graph_request.js
new file mode 100644
index 0000000..055fc1c
--- /dev/null
+++ b/static/topology3D/js/graph_request.js
@@ -0,0 +1,318 @@
+/*
+ Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+if (typeof dreamer === 'undefined') {
+ var dreamer = {};
+}
+var level = {}
+
+dreamer.GraphRequests = (function(global) {
+ 'use strict';
+
+ var DEBUG = true;
+
+ GraphRequests.prototype.constructor = GraphRequests;
+
+ /**
+ * Constructor
+ */
+ function GraphRequests(args) {
+
+
+ }
+
+ GraphRequests.prototype.addNode = function(args, choice, success, error) {
+ var data = new FormData();
+ data.append('csrfmiddlewaretoken', this.getCookie('csrftoken'));
+
+ data = args_to_formdata(args, data);
+
+ //FIXME questo metodo dovrebbere essere generico
+ if(args.existing_element)
+ data.append('existing_element', args.existing_element ? args.existing_element : false)
+ //if (choice)
+ // data.append('choice', choice);
+ $.ajax({
+ url: "addelement",
+ type: 'POST',
+ data: data,
+ cache: false,
+ contentType: false,
+ processData: false,
+ success: function(result) {
+ if (success)
+ success();
+ },
+ error: function(result) {
+ if (error)
+ error(result);
+ log("some error: " + result);
+ }
+ });
+ };
+
+ GraphRequests.prototype.removeNode = function(args, choice, success, error) {
+ var data = new FormData();
+ data.append('csrfmiddlewaretoken', this.getCookie('csrftoken'));
+
+ data = args_to_formdata(args, data);
+
+ $.ajax({
+ url: "removeelement",
+ type: 'POST',
+ data: data,
+ cache: false,
+ contentType: false,
+ processData: false,
+ success: function(result) {
+ if (success)
+ success();
+ },
+ error: function(result) {
+ if (error)
+ error(result);
+ }
+ });
+ };
+
+ GraphRequests.prototype.getNodeOverview = function(args, success, error) {
+
+ var params = jQuery.param(args)
+ console.log("params", params)
+ $.ajax({
+ url: "overviewelement?"+params,
+ type: 'GET',
+ success: function(result) {
+ if (success)
+ success(result);
+ },
+ error: function(result) {
+ if (error)
+ error(result);
+ }
+ });
+ };
+
+ GraphRequests.prototype.addLink = function(args, choice, success, error) {
+ var data = new FormData();
+ data.append('csrfmiddlewaretoken', this.getCookie('csrftoken'));
+ data = args_to_formdata(args, data);
+
+ //data.append('destination', JSON.stringify(destination));
+ if (choice)
+ data.append('choice', choice);
+ //if(link.desc_id)
+ // data.append('element_desc_id', link.desc_id || '');
+ $.ajax({
+ url: "addlink",
+ type: 'POST',
+ data: data,
+ cache: false,
+ contentType: false,
+ processData: false,
+ success: function(result) {
+ if (success)
+ success();
+ },
+ error: function(result) {
+ if (error)
+ error(result);
+ log("some error: " + result);
+ }
+ });
+ };
+
+ GraphRequests.prototype.removeLink = function(args, success, error) {
+ var data = new FormData();
+ data.append('csrfmiddlewaretoken', this.getCookie('csrftoken'));
+ data = args_to_formdata(args, data);
+
+ $.ajax({
+ url: "removelink",
+ type: 'POST',
+ data: data,
+ cache: false,
+ contentType: false,
+ processData: false,
+ success: function(result) {
+ if (success)
+ success();
+ },
+ error: function(result) {
+ if (error)
+ error(result);
+ log("some error: " + result);
+ }
+ });
+ };
+
+ //
+ GraphRequests.prototype.getAvailableNodes = function(args, success, error){
+ var data = new FormData();
+ data.append('csrfmiddlewaretoken', this.getCookie('csrftoken'));
+ $.ajax({
+ url: "availablenodes?layer="+args.layer,
+ type: 'GET',
+ success: function(result) {
+ if (success)
+ success(result);
+ },
+ error: function(result) {
+ if (error)
+ error(result);
+ log("some error: " + result);
+ }
+ });
+ }
+
+ GraphRequests.prototype.savePositions = function(positions, success, error) {
+ var data = new FormData();
+ data.append('csrfmiddlewaretoken', this.getCookie('csrftoken'));
+ data.append('positions', JSON.stringify(positions));
+ $.ajax({
+ url: "positions",
+ type: 'POST',
+ data: data,
+ cache: false,
+ contentType: false,
+ processData: false,
+ success: function(result) {
+ if (success)
+ success();
+ },
+ error: function(result) {
+ if (error)
+ error(result);
+ log("some error: " + result);
+ }
+ });
+ };
+
+ /* START ETSI methods */
+ GraphRequests.prototype.addVnffg = function(args, success, error) {
+ var data = new FormData();
+ data.append('csrfmiddlewaretoken', this.getCookie('csrftoken'));
+ /* data.append('group_id', args.info.group[0]);
+ data.append('element_id', args.id);
+ data.append('element_type', args.info.type);*/
+ data = args_to_formdata(args, data);
+ $.ajax({
+ url: "addelement",
+ type: 'POST',
+ data: data,
+ cache: false,
+ contentType: false,
+ processData: false,
+ success: function(result) {
+ if (success)
+ success(result);
+ },
+ error: function(result) {
+ if (error)
+ error(result);
+ log("some error: " + result);
+ }
+ });
+ };
+
+ GraphRequests.prototype.addNodeToVnffg = function(args, success, error) {
+ var data = new FormData();
+ data.append('csrfmiddlewaretoken', this.getCookie('csrftoken'));
+ /* data.append('group_id', args.info.group[0]);
+ data.append('element_id', args.id);
+ data.append('element_type', args.info.type);
+ data.append('vnffg_id', args.vnffgId);*/
+ data = args_to_formdata(args, data);
+
+ $.ajax({
+ url: "addnodetovnffg",
+ type: 'POST',
+ data: data,
+ cache: false,
+ contentType: false,
+ processData: false,
+ success: function(result) {
+ if (success)
+ success(result);
+ },
+ error: function(result) {
+ if (error)
+ error(result);
+ log("some error: " + result);
+ }
+ });
+ };
+
+ GraphRequests.prototype.getUnusedVnf = function(nsd_id, success, error) {
+ var data = new FormData();
+ data.append('csrfmiddlewaretoken', this.getCookie('csrftoken'));
+ $.ajax({
+ url: "unusedvnf/" + nsd_id,
+ type: 'GET',
+ success: function(result) {
+ if (success)
+ success(result);
+ },
+ error: function(result) {
+ if (error)
+ error(result);
+ log("some error: " + result);
+ }
+ });
+
+ };
+ /* END ETSI methods */
+
+ GraphRequests.prototype.getCookie = function(name) {
+ var cookieValue = null;
+ if (document.cookie && document.cookie !== '') {
+ var cookies = document.cookie.split(';');
+ for (var i = 0; i < cookies.length; i++) {
+ var cookie = jQuery.trim(cookies[i]);
+ // Does this cookie string begin with the name we want?
+ if (cookie.substring(0, name.length + 1) === (name + '=')) {
+ cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+ break;
+ }
+ }
+ }
+ return cookieValue;
+ };
+
+ function args_to_formdata(args, form_data){
+ for ( var key in args ) {
+ form_data.append(key, args[key]);
+ }
+ return form_data;
+ };
+
+
+ /**
+ * Log utility
+ */
+ function log(text) {
+ if (DEBUG)
+ console.log("::GraphRequests::", text);
+ }
+
+ return GraphRequests;
+
+
+}(this));
+
+if (typeof module === 'object') {
+ module.exports = dreamer.GraphRequests;
+}
diff --git a/static/topology3D/js/model_graph_editor.js b/static/topology3D/js/model_graph_editor.js
new file mode 100644
index 0000000..3c275dd
--- /dev/null
+++ b/static/topology3D/js/model_graph_editor.js
@@ -0,0 +1,512 @@
+/*
+ Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+if (typeof dreamer === 'undefined') {
+ var dreamer = {};
+}
+var level = {}
+
+dreamer.ModelGraphEditor = (function (global) {
+ 'use strict';
+
+ var DEBUG = true;
+ var SHIFT_BUTTON = 16;
+ var IMAGE_PATH = "/static/assets/img/";
+ var GUI_VERSION = "v1";
+
+
+ ModelGraphEditor.prototype = new dreamer.GraphEditor();
+ ModelGraphEditor.prototype.constructor = ModelGraphEditor;
+ ModelGraphEditor.prototype.parent = dreamer.GraphEditor.prototype;
+
+ /**
+ * Constructor
+ */
+ function ModelGraphEditor(args) {
+
+ log("Constructor");
+
+ }
+
+
+ ModelGraphEditor.prototype.init = function (args) {
+ this.parent.init.call(this, args);
+
+ if (args.gui_properties[GUI_VERSION] != undefined) {
+ args.gui_properties = args.gui_properties[GUI_VERSION];
+ }
+
+ this.desc_id = args.desc_id || undefined;
+ this.type_property = {};
+ this.type_property["unrecognized"] = args.gui_properties["default"];
+ this.type_property["unrecognized"]["default_node_label_color"] = args.gui_properties["default"]["label_color"];
+ //this.type_property["unrecognized"]["shape"] = d3.symbolCross;
+ this._edit_mode = (args.edit_mode != undefined) ? args.edit_mode : this._edit_mode;
+
+ Object.keys(args.gui_properties["nodes"]).forEach(function (key, index) {
+ this.type_property[key] = args.gui_properties["nodes"][key];
+ if ( this.type_property[key]['property'] != undefined){
+ for(var c_prop in this.type_property[key]){
+ if(c_prop != 'property'){
+
+ this.type_property[key][c_prop]['shape'] = this.parent.get_d3_symbol(this.type_property[key][c_prop]['shape']);
+ if(this.type_property[key][c_prop]["image"] != undefined){
+ this.type_property[key][c_prop]["image"] = IMAGE_PATH + this.type_property[key][c_prop]["image"]
+ }
+ }
+ }
+ }
+ else{
+ this.type_property[key]["shape"] = this.parent.get_d3_symbol(this.type_property[key]["shape"]);
+ if (this.type_property[key]["image"] != undefined) {
+ this.type_property[key]["image"] = IMAGE_PATH + this.type_property[key]["image"];
+ }
+ }
+
+
+
+ }, this);
+ if(args.gui_properties["edges"]){
+ this.type_property_link = args.gui_properties["edges"];
+ var self = this;
+ var link_types = ['unrecognized'].concat(Object.keys(self.type_property_link))
+ this.defs.selectAll("marker")
+ .data(link_types)
+ .enter()
+ .append("svg:marker") // This section adds in the arrows
+ .attr("id", function(d){
+ return d;
+ })
+ .attr("viewBox", "-5 -5 10 10")
+ .attr("refX", 13) /*must be smarter way to calculate shift*/
+ .attr("refY", 0)
+ .attr("markerUnits", "userSpaceOnUse")
+ .attr("markerWidth", 12)
+ .attr("markerHeight", 12)
+ .attr("orient", "auto")
+ .append("path")
+ .attr("d", "M 0,0 m -5,-5 L 5,0 L -5,5 Z")
+ .attr('fill', function(d){
+ return self.type_property_link[d].color;
+ });
+ }
+
+ this.customBehavioursOnEvents = args.behaviorsOnEvents || undefined;
+
+ var self = this;
+ var data_url = (args.data_url) ? args.data_url : "graph_data/";
+ if (!args.graph_data) {
+ d3.json(data_url, function (error, data) {
+ //console.log(JSON.stringify(data))
+ self.d3_graph.nodes = data.vertices;
+ self.d3_graph.links = data.edges;
+ self.d3_graph.graph_parameters = data.graph_parameters;
+ self.model = data.model;
+ self.refreshGraphParameters(self.d3_graph.graph_parameters);
+ self.refresh();
+ self.startForce();
+ //if(args.filter_base != undefined)
+
+ setTimeout(function () {
+ //self.handleForce(self.forceSimulationActive);
+ //var f_t = {"node":{"type":[],"group":["vlan_r3u0"]},"link":{"group":["vlan_r3u0"],"view":[""]}}
+ //var f_t ={"node":{"type":["vnf_vl","vnf_ext_cp","vnf_vdu_cp","vnf_vdu","vnf_click_vdu"],"group":["vlan_r3u0"]},"link":{"group":["vlan_r3u0"],"view":["vnf"]}}
+ self.handleFiltersParams(args.filter_base);
+ //self.handleFiltersParams(f_t);
+ //console.log(JSON.stringify(args.filter_base))
+ //console.log(self.d3_graph.nodes.length)
+ //console.log(JSON.stringify(self.d3_graph.nodes))
+ //self.d3_graph.nodes.forEach(function(key, index){
+ //console.log(key, index);
+ //})
+ }, 500);
+
+ });
+ } else {
+ this.updateData(args)
+ }
+ }
+
+ /**
+ * Update data of the graph.
+ * @param {Object} Required. An object that specifies tha data of the new node.
+ * @returns {boolean}
+ */
+ ModelGraphEditor.prototype.updateData = function (args) {
+ console.log("updateData")
+ this.d3_graph.nodes = args.graph_data.vertices;
+ this.d3_graph.links = args.graph_data.edges;
+ this.d3_graph.graph_parameters = args.graph_parameters;
+ this.model = args.model;
+ this.refreshGraphParameters(this.d3_graph.graph_parameters);
+ this.refresh();
+ this.startForce();
+ //if(args.filter_base != undefined)
+
+ //if(args.filter_base){
+ var self = this;
+ setTimeout(function () {
+ self.handleForce(true);
+ self.handleFiltersParams(args.filter_base);
+ }, 500);
+ //}
+ }
+
+ /**
+ * Add a new node to the graph.
+ * @param {Object} Required. An object that specifies tha data of the new node.
+ * @returns {boolean}
+ */
+ ModelGraphEditor.prototype.addNode = function (node, success, error) {
+ var self = this;
+ var current_layer = self.getCurrentView();
+ var node_type = node.info.type;
+
+ if (self.model.layer[current_layer] && self.model.layer[current_layer].nodes[node_type] && self.model.layer[current_layer].nodes[node_type].addable) {
+ if (self.model.layer[current_layer].nodes[node_type].addable.callback) {
+ var c = self.model.callback[self.model.layer[current_layer].nodes[node_type].addable.callback].class;
+ var controller = new dreamer[c]();
+ controller[self.model.layer[current_layer].nodes[node_type].addable.callback](self, node, function () {
+ self.parent.addNode.call(self, node);
+ success && success();
+ }, error);
+
+ } else {
+
+ log('addNode: callback undefined in model spec.');
+ error && error("You can't add a " + node.info.type + ", callback undefined.");
+ }
+ } else {
+ //FIXME Error handling????
+ log("You can't add a " + node.info.type + " in a current layer " + current_layer);
+ error && error("You can't add a " + node.info.type + " in a current layer " + current_layer);
+ }
+ };
+
+
+
+ /**
+ * Update the data properties of the node
+ * @param {Object} Required. An object that specifies tha data of the node.
+ * @returns {boolean}
+ */
+ ModelGraphEditor.prototype.updateDataNode = function (args) {
+ //FIXME updating a node properties need commit to server side!
+ this.parent.updateDataNode.call(this, args);
+ };
+
+ /**
+ * Remove a node from graph and related links.
+ * @param {String} Required. Id of node to remove.
+ * @returns {boolean}
+ */
+ ModelGraphEditor.prototype.removeNode = function (node, success, error) {
+ console.log('removeNode', JSON.stringify(node))
+ var self = this;
+ var current_layer = self.getCurrentView();
+ var node_type = node.info.type;
+ if (node.info.desc_id == undefined){
+ node.info.desc_id = self.desc_id;
+ }
+ if (self.model.layer[current_layer] && self.model.layer[current_layer].nodes[node_type] && self.model.layer[current_layer].nodes[node_type].removable) {
+ if (self.model.layer[current_layer].nodes[node_type].removable.callback) {
+ var c = self.model.callback[self.model.layer[current_layer].nodes[node_type].removable.callback].class;
+ var controller = new dreamer[c]();
+ controller[self.model.layer[current_layer].nodes[node_type].removable.callback](self, node, function () {
+ self.parent.removeNode.call(self, node);
+ success && success();
+ }, error);
+ } else {
+
+ log('removeNode: callback undefined in model spec.');
+ error && error("You can't remove a " + node.info.type + ", callback undefined.");
+ }
+ } else {
+ //FIXME we need to manage alert in a different way: FAILBACK
+ log("You can't remove a " + node.info.type);
+ error && error("You can't remove a " + node.info.type);
+ }
+ };
+
+ /**
+ * Add a new link to graph.
+ * @param {Object} Required. An object that specifies tha data of the new Link.
+ * @returns {boolean}
+ */
+ ModelGraphEditor.prototype.addLink = function (s, d, success, error) {
+ var self = this;
+ var source_id = s.id;
+ var target_id = d.id;
+ var source_type = s.info.type;
+ var destination_type = d.info.type;
+ var link = {
+ source: s,
+ target: d,
+ view: this.filter_parameters.link.view[0],
+ group: this.filter_parameters.link.group,
+ desc_id: this.desc_id
+ };
+ log("addLink: " + JSON.stringify(link))
+ var current_layer = self.getCurrentView()
+ if (self.model.layer[current_layer].allowed_edges && self.model.layer[current_layer].allowed_edges[source_type] && self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type]) {
+
+ if (self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type].callback) {
+ var callback = self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type].callback;
+ console.log(callback, self.model.callback)
+ var direct_edge = 'direct_edge' in self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type] ? self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type]['direct_edge'] : false;
+ link.directed_edge = direct_edge;
+ var c = self.model.callback[callback].class;
+ var controller = new dreamer[c]();
+ controller[callback](self, link, function () {
+ self._deselectAllNodes();
+ self.parent.addLink.call(self, link);
+ if (success)
+ success();
+ }, error);
+ } else {
+ log('addLink: callback undefined in model spec.');
+ error && error("You can't add a link, callback undefined.");
+ }
+
+ } else {
+ //FIXME we need to manage alert in a different way: FAILBACK
+ log("You can't link a " + source_type + " with a " + destination_type);
+
+ error && error("You can't link a " + source_type + " with a " + destination_type);
+ }
+ };
+
+ /**
+ * Remove a link from graph.
+ * @param {String} Required. The identifier of link to remove.
+ * @returns {boolean}
+ */
+ ModelGraphEditor.prototype.removeLink = function (link, success, error) {
+ var self = this;
+ var s = link.source;
+ var d = link.target;
+ var source_type = s.info.type;
+ var destination_type = d.info.type;
+ var current_layer = self.getCurrentView()
+ if (self.model.layer[current_layer].allowed_edges && self.model.layer[current_layer].allowed_edges[source_type] && self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type] &&
+ self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type].removable
+ ) {
+ if (self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type].removable.callback) {
+ var callback = self.model.layer[current_layer].allowed_edges[source_type].destination[destination_type].removable.callback;
+ var c = self.model.callback[callback].class;
+ var controller = new dreamer[c]();
+ controller[callback](self, link, function () {
+ self._deselectAllNodes();
+ self._deselectAllLinks();
+ self.parent.removeLink.call(self, link.index);
+ success && success();
+ }, error);
+ } else {
+ log('removeLink: callback undefined in model spec.');
+ error && error("You can't remove a link, callback undefined.");
+ }
+
+ } else {
+ //FIXME we need to manage alert in a different way: FAILBACK
+ log("You can't delete the link");
+ error && error("You can't delete the link");
+ }
+
+
+ };
+
+
+ ModelGraphEditor.prototype.savePositions = function (data) {
+ var vertices = {}
+ this.node.each(function (d) {
+ vertices[d.id] = {}
+ vertices[d.id]['x'] = d.x;
+ vertices[d.id]['y'] = d.y;
+ });
+ new dreamer.GraphRequests().savePositions({
+ 'vertices': vertices
+ });
+
+ }
+
+ /**
+ * Internal functions
+ */
+
+ /**
+ *
+ *
+ */
+
+ ModelGraphEditor.prototype._setupBehaviorsOnEvents = function (layer) {
+
+ var self = this;
+ var contextMenuLinksAction = [{
+ title: 'Delete Link',
+ action: function (elm, link, i) {
+ self.removeLink(link, null, showAlert);
+ },
+ edit_mode: true
+ }];
+ var contextMenuNodesAction = [{
+ title: 'Edit',
+ action: function (elm, d, i) {
+ if (d.info.type != undefined) {
+ self.eventHandler.fire("edit_descriptor", self.project_id, d);
+ }
+ },
+ nodes: [],
+ edit_mode: true
+ },
+ {
+ title: 'Delete',
+ action: function (elm, d, i) {
+ self.removeNode(d, null, showAlert);
+ },
+ edit_mode: true
+ },
+
+ ];
+ if(this.customBehavioursOnEvents){
+ contextMenuNodesAction = contextMenuNodesAction.concat(this.customBehavioursOnEvents['behaviors'].nodes);
+ }
+
+
+ if ( self.model && self.model.layer && self.model.layer[layer] && self.model.layer[layer].action && self.model.layer[layer].action.node) {
+ for (var i in self.model.layer[layer].action.node) {
+ var action = self.model.layer[layer].action.node[i]
+ contextMenuNodesAction.push({
+ title: action.title,
+ action: function (elm, d, i) {
+ var callback = action.callback;
+ var c = self.model.callback[callback].class;
+ var controller = new dreamer[c]();
+ var args = {
+ elm: elm,
+ d: d,
+ i: i
+ }
+
+ controller[callback](self, args);
+ },
+ edit_mode: (action.edit_mode != undefined) ? action.edit_mode: undefined
+ });
+ }
+ }
+
+ this.behavioursOnEvents = {
+ 'nodes': {
+ 'click': function (d) {
+
+ d3.event.preventDefault();
+
+ if (self._edit_mode && self.lastKeyDown == SHIFT_BUTTON && self._selected_node != undefined) {
+ self.addLink(self._selected_node, d, null, showAlert);
+ } else {
+ self._selectNodeExclusive(this, d);
+ }
+
+ },
+ 'mouseover': function (d) {
+ self.link.style('stroke-width', function (l) {
+ if (d === l.source || d === l.target)
+ return 4;
+ else
+ return 2;
+ });
+ },
+ 'mouseout': function (d) {
+ self.link.style('stroke-width', 2);
+ },
+ 'contextmenu': d3.contextMenu(contextMenuNodesAction, {
+ 'edit_mode': self._edit_mode,
+ 'layer': layer,
+ 'type_object': 'node'
+ })
+ },
+ 'links': {
+ 'click': function (d) {
+ self._selectLinkExclusive(this, d);
+
+ },
+ 'dblclick': function (event) {
+
+ },
+ 'mouseover': function (d) {
+ d3.select(this).style('stroke-width', 4);
+ },
+ 'mouseout': function (d) {
+ if (d != self._selected_link)
+ d3.select(this).style('stroke-width', 2);
+ },
+ 'contextmenu': d3.contextMenu(contextMenuLinksAction, {
+ 'edit_mode': self._edit_mode,
+ 'layer': layer,
+ 'type_object': 'link'
+ })
+ }
+ }
+ };
+
+ ModelGraphEditor.prototype.handleFiltersParams = function (filtersParams, notFireEvent) {
+
+ this.parent.handleFiltersParams.call(this, filtersParams, notFireEvent);
+ this._setupBehaviorsOnEvents(filtersParams.link.view[0]);
+ };
+
+ ModelGraphEditor.prototype.getAvailableNodes = function () {
+ log('getAvailableNodes');
+ log(this.model)
+ if (this.model && this.model.layer[this.getCurrentView()] != undefined)
+ return this.model.layer[this.getCurrentView()].nodes;
+ return [];
+ }
+
+
+ ModelGraphEditor.prototype.exploreLayer = function (args) {
+
+ };
+
+ ModelGraphEditor.prototype.getTypeProperty = function () {
+ return this.type_property;
+ };
+
+ ModelGraphEditor.prototype.getCurrentGroup = function () {
+ return this.filter_parameters.node.group[0];
+
+ }
+
+ ModelGraphEditor.prototype.getCurrentView = function () {
+ return this.filter_parameters.link.view[0];
+
+ }
+ /**
+ * Log utility
+ */
+ function log(text) {
+ if (DEBUG)
+ console.log("::ModelGraphEditor::", text);
+ }
+
+
+
+ return ModelGraphEditor;
+
+
+}(this));
+
+if (typeof module === 'object') {
+ module.exports = dreamer.ModelGraphEditor;
+}
\ No newline at end of file