552 lines
23 KiB
HTML
552 lines
23 KiB
HTML
{% extends 'navbar/navbar.html' %}
|
|
{% load static %}
|
|
{% block home %}
|
|
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<link rel="stylesheet" href="{% static 'ddos/css/ddos.css' %}">
|
|
<title>x-sys</title>
|
|
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
|
|
<style>
|
|
h2{
|
|
|
|
color:white
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="ipSection">
|
|
<h2 class="ipNumber">DDos</h2>
|
|
</div>
|
|
<div class="gridGraphSection ">
|
|
<div class="chartOpenClose">
|
|
<div class="tabSectionHeader">
|
|
<p class="tabTitle">AI training graphs</p>
|
|
<span class="svgIcon">
|
|
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M0 25C0 11.1929 11.1929 0 25 0V0C38.8071 0 50 11.1929 50 25V25C50 38.8071 38.8071 50 25 50V50C11.1929 50 0 38.8071 0 25V25Z" fill="#0C7DB1" fill-opacity="0.7"/>
|
|
<path d="M14 20L25 31L36 20" stroke="white" stroke-width="4" stroke-linecap="round"/>
|
|
</svg>
|
|
</span>
|
|
</div>
|
|
<div>
|
|
<div id="columnchart_values" style="width:100% ;height:450px;display: flex;align-items:center;justify-content: center;"></div>
|
|
</div>
|
|
<div id="barchart_values" style="width:100% ;height:450px;display: flex;align-items:center;justify-content: center;"></div>
|
|
<div id="chart_div" style="width:100% ;height:450px;display: flex;align-items:center;justify-content: center;"></div>
|
|
<div id="StackedColumnsChart" style="width:100% ;height:450px;display: flex;align-items:center;justify-content: center;"></div>
|
|
<!-- <div id="DurationChart" style="width: 100%; height:500px"></div> -->
|
|
</div>
|
|
<div class="chartOpenClose">
|
|
<div class="tabSectionHeader">
|
|
<p class="tabTitle">Graphical Analysis for AI Training of Individual DDoS Parameters</p>
|
|
<span class="svgIcon">
|
|
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M0 25C0 11.1929 11.1929 0 25 0V0C38.8071 0 50 11.1929 50 25V25C50 38.8071 38.8071 50 25 50V50C11.1929 50 0 38.8071 0 25V25Z" fill="#0C7DB1" fill-opacity="0.7"/>
|
|
<path d="M14 20L25 31L36 20" stroke="white" stroke-width="4" stroke-linecap="round"/>
|
|
</svg>
|
|
</span>
|
|
</div>
|
|
<div id="TransmittedChart" style="width:100% ;height:450px;display: flex;align-items:center;justify-content: center;"></div>
|
|
<div id="TransmittedBytesChart" style="width:100% ;height:450px;display: flex;align-items:center;justify-content: center;" ></div>
|
|
<!-- <div id="SwitchChart" style="width: 100%; height:500px"></div> -->
|
|
</div>
|
|
<div class="chartOpenClose">
|
|
<div class="tabSectionHeader">
|
|
<p class="tabTitle">DDoS Attack Type</p>
|
|
<span class="svgIcon">
|
|
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M0 25C0 11.1929 11.1929 0 25 0V0C38.8071 0 50 11.1929 50 25V25C50 38.8071 38.8071 50 25 50V50C11.1929 50 0 38.8071 0 25V25Z" fill="#0C7DB1" fill-opacity="0.7"/>
|
|
<path d="M14 20L25 31L36 20" stroke="white" stroke-width="4" stroke-linecap="round"/>
|
|
</svg>
|
|
</span>
|
|
</div>
|
|
<div class="chartTitleLable">
|
|
<p><span></span>BENIGN</p>
|
|
<p><span></span>MSSQL</p>
|
|
<p><span></span>Portmap</p>
|
|
<p><span></span>NetBIOS</p>
|
|
<p><span></span>UDP</p>
|
|
<p><span></span>Syn</p>
|
|
<p><span></span>UDPLag</p>
|
|
</div>
|
|
<div id="PieSliceChart" style="width: 100%; height:500px"></div>
|
|
<div id="LineColumnsChart" style="width: 100%; height:500px"></div>
|
|
<div id="LineFlowDurationChart" style="width: 100%; height:500px"></div>
|
|
<div style="margin-bottom:50px">
|
|
<div id="columnInThreeChart" style="width: 95%;"></div>
|
|
</div>
|
|
<div style="margin-bottom:50px">
|
|
<div id="columnInHTTPChart" style="width: 95%; height:500px"></div>
|
|
</div>
|
|
</div>
|
|
<div class="chartOpenClose">
|
|
<div class="tabSectionHeader">
|
|
<p class="tabTitle">Number of Attack request</p>
|
|
<span class="svgIcon">
|
|
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M0 25C0 11.1929 11.1929 0 25 0V0C38.8071 0 50 11.1929 50 25V25C50 38.8071 38.8071 50 25 50V50C11.1929 50 0 38.8071 0 25V25Z" fill="#0C7DB1" fill-opacity="0.7"/>
|
|
<path d="M14 20L25 31L36 20" stroke="white" stroke-width="4" stroke-linecap="round"/>
|
|
</svg>
|
|
</span>
|
|
</div>
|
|
<div class="chart-flex">
|
|
<div id="barchart_attack" style="width:100% ;height:500px;display: flex;align-items:center;justify-content: center;"></div>
|
|
</div>
|
|
</div>
|
|
<div class="chartOpenClose">
|
|
<div class="tabSectionHeader">
|
|
<p class="tabTitle">DDoS Visualization</p>
|
|
<span class="svgIcon">
|
|
<svg width="50" height="50" viewBox="0 0 50 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
<path d="M0 25C0 11.1929 11.1929 0 25 0V0C38.8071 0 50 11.1929 50 25V25C50 38.8071 38.8071 50 25 50V50C11.1929 50 0 38.8071 0 25V25Z" fill="#0C7DB1" fill-opacity="0.7"/>
|
|
<path d="M14 20L25 31L36 20" stroke="white" stroke-width="4" stroke-linecap="round"/>
|
|
</svg>
|
|
</span>
|
|
</div>
|
|
<div class="chart-flex" style="padding:10px">
|
|
<div id="ScatterDDoSPCAChart" style="width: 100%; height:500px"></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script src="{% static 'navbar/js/jquery-3.7.0.js' %}"></script>
|
|
<script src="{% static 'ddos/js/pieChart.js'%}"></script>
|
|
<script type="application/json" id="ddos-sums">{{ ddos_sums|safe }}</script>
|
|
<script type="text/javascript">
|
|
google.charts.load("current", { packages: ['corechart'] });
|
|
google.charts.setOnLoadCallback(drawChart);
|
|
|
|
function drawChart() {
|
|
|
|
// Fetch the DDoS data from the application/json script tag
|
|
ddos_data = document.getElementById('ddos-sums').textContent;
|
|
ddos_data = ddos_data.replace(/'/g, '"');
|
|
console.log(ddos_data);
|
|
var ddosData = JSON.parse(ddos_data)
|
|
|
|
// Prepare the data for Google Charts
|
|
// var data = google.visualization.arrayToDataTable([
|
|
// ["Element", "Density", { role: "style" }],
|
|
// ["pktcount", ddosData['pktcount'], "#1EBBC7"],
|
|
// ["byteperflow", ddosData['byteperflow'], "#1E51C7"],
|
|
// ["tot_kbps", ddosData['tot_kbps'], "#1D86C7"],
|
|
// ["rx_kbps", ddosData['rx_kbps'], "#1EC79A"],
|
|
// ["flows", ddosData['flows'], "#201EC7"],
|
|
// ["bytecount", ddosData['bytecount'], "#54A3A8"],
|
|
// ["tot_dur", ddosData['tot_dur'], "#546DA8"]
|
|
// ]);
|
|
var data = google.visualization.arrayToDataTable([
|
|
["Element", "Density", { role: "style" }],
|
|
["pktcount", ddosData['pktcount'] || 0, "#1EBBC7"], // Default to 0 if undefined
|
|
["byteperflow", ddosData['byteperflow'] || 0, "#1E51C7"],
|
|
["tot_kbps", ddosData['tot_kbps'] || 0, "#1D86C7"],
|
|
["rx_kbps", ddosData['rx_kbps'] || 0, "#1EC79A"],
|
|
["flows", ddosData['flows'] || 0, "#201EC7"],
|
|
["bytecount", ddosData['bytecount'] || 0, "#54A3A8"],
|
|
["tot_dur", ddosData['tot_dur'] || 0, "#546DA8"]
|
|
]);
|
|
|
|
var view = new google.visualization.DataView(data);
|
|
view.setColumns([0, 1, 2]);
|
|
|
|
var options = {
|
|
title: "DDoS Attack Data",
|
|
bar: { groupWidth: "95%" },
|
|
legend: { position: "none" },
|
|
backgroundColor: '#0c212b',
|
|
tooltip: { trigger: 'none' },
|
|
vAxis: {
|
|
title: 'Count',
|
|
viewWindow: {
|
|
min: 0,
|
|
max: 3000
|
|
}
|
|
}
|
|
};
|
|
|
|
// Draw the chart in the specified div
|
|
var chart = new google.visualization.ColumnChart(document.getElementById("columnchart_values"));
|
|
chart.draw(view, options);
|
|
}
|
|
</script>
|
|
<script id="srcIpData" type="application/json">
|
|
{{ src_ip_dict|safe }}
|
|
</script>
|
|
|
|
<script>
|
|
google.charts.load("current", { packages: ["corechart"] });
|
|
google.charts.setOnLoadCallback(drawChart);
|
|
|
|
function drawChart() {
|
|
// Fetch and parse the JSON data from the script tag
|
|
console.log("xd");
|
|
var ddos_data = document.getElementById('srcIpData').textContent;
|
|
ddos_data = ddos_data.replace(/'/g, '"');
|
|
|
|
|
|
var srcIpDict = JSON.parse(ddos_data);
|
|
|
|
|
|
function getChartData() {
|
|
var data = [["Source IP", "Count", { role: "style" }]];
|
|
|
|
// Iterate over the srcIpDict and push the IPs and their counts into the data array
|
|
for (var ip in srcIpDict) {
|
|
if (srcIpDict.hasOwnProperty(ip)) {
|
|
data.push([ip, srcIpDict[ip], "#1E51C7"]); // Color can be changed as needed
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
function drawDynamicChart() {
|
|
var data = google.visualization.arrayToDataTable(getChartData());
|
|
|
|
var view = new google.visualization.DataView(data);
|
|
view.setColumns([0, 1,
|
|
{
|
|
calc: "stringify",
|
|
sourceColumn: 1,
|
|
type: "string",
|
|
role: "annotation"
|
|
},
|
|
2
|
|
]);
|
|
|
|
var options = {
|
|
title: "Source IP Requests",
|
|
bar: { groupWidth: "95%" },
|
|
legend: { position: "none" },
|
|
backgroundColor: '#0c212b',
|
|
tooltip: { trigger: 'none' },
|
|
hAxis: {
|
|
viewWindow: {
|
|
min: 0,
|
|
max: Math.max(...Object.values(srcIpDict)) + 10 // Adjust the max dynamically
|
|
}
|
|
}
|
|
};
|
|
|
|
var chart = new google.visualization.BarChart(document.getElementById("barchart_values"));
|
|
chart.draw(view, options);
|
|
}
|
|
drawDynamicChart();
|
|
}
|
|
|
|
|
|
// Initial draw
|
|
|
|
</script>
|
|
|
|
<script id="destIpData" type="application/json">
|
|
{{ dest_ip_dict|safe }}
|
|
</script>
|
|
|
|
<script>
|
|
google.charts.load("current", { packages: ["corechart"] });
|
|
google.charts.setOnLoadCallback(drawChart);
|
|
|
|
function drawChart() {
|
|
// Fetch and parse the JSON data from the script tag
|
|
|
|
var ddos_data = document.getElementById('destIpData').textContent;
|
|
ddos_data = ddos_data.replace(/'/g, '"');
|
|
|
|
|
|
var srcIpDict = JSON.parse(ddos_data);
|
|
|
|
|
|
function getChartData() {
|
|
var data = [["Destination IP", "Count", { role: "style" }]];
|
|
|
|
// Iterate over the srcIpDict and push the IPs and their counts into the data array
|
|
for (var ip in srcIpDict) {
|
|
if (srcIpDict.hasOwnProperty(ip)) {
|
|
data.push([ip, srcIpDict[ip], "#1E51C7"]); // Color can be changed as needed
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
function drawDynamicChart() {
|
|
var data = google.visualization.arrayToDataTable(getChartData());
|
|
|
|
var view = new google.visualization.DataView(data);
|
|
view.setColumns([0, 1,
|
|
{
|
|
calc: "stringify",
|
|
sourceColumn: 1,
|
|
type: "string",
|
|
role: "annotation"
|
|
},
|
|
2
|
|
]);
|
|
|
|
var options = {
|
|
title: "Number of all outgoing request",
|
|
bar: { groupWidth: "95%" },
|
|
legend: { position: "none" },
|
|
backgroundColor: '#0c212b',
|
|
tooltip: { trigger: 'none' },
|
|
hAxis: {
|
|
viewWindow: {
|
|
min: 0,
|
|
max: Math.max(...Object.values(srcIpDict)) + 10 // Adjust the max dynamically
|
|
}
|
|
}
|
|
};
|
|
|
|
var chart = new google.visualization.BarChart(document.getElementById("chart_div"));
|
|
chart.draw(view, options);
|
|
}
|
|
drawDynamicChart();
|
|
}
|
|
|
|
|
|
// Initial draw
|
|
|
|
</script>*
|
|
<script type="application/json" id="protocolData">
|
|
{{ protocol_counts | safe }}
|
|
</script>
|
|
|
|
<script>
|
|
google.charts.load('current', { 'packages': ['corechart'] });
|
|
google.charts.setOnLoadCallback(drawChart);
|
|
|
|
function drawChart() {
|
|
// Fetching the protocol data from the JSON script tag
|
|
var ddos_data = document.getElementById('protocolData').textContent;
|
|
ddos_data = ddos_data.replace(/'/g, '"');
|
|
|
|
|
|
var protocolData = JSON.parse(ddos_data);
|
|
|
|
// Prepare the DataTable and columns
|
|
var data = new google.visualization.DataTable();
|
|
data.addColumn('string', 'Protocol');
|
|
data.addColumn('number', 'Requests');
|
|
|
|
// Adding rows dynamically based on protocolData from Django
|
|
Object.keys(protocolData).forEach(function(protocol) {
|
|
data.addRow([protocol, protocolData[protocol]]);
|
|
});
|
|
|
|
// Chart options
|
|
var options = {
|
|
title: 'The number of requests from different protocols',
|
|
isStacked: true,
|
|
vAxis: {
|
|
minValue: 0,
|
|
maxValue: 20 // Adjust this according to your data range
|
|
},
|
|
backgroundColor: '#0c212b',
|
|
tooltip: { trigger: 'none' },
|
|
colors: ['#1D86C7'],
|
|
legend: { position: "none" }
|
|
};
|
|
|
|
// Create the chart
|
|
var chart = new google.visualization.ColumnChart(document.getElementById('StackedColumnsChart'));
|
|
chart.draw(data, options);
|
|
}
|
|
</script>
|
|
<script id="srcIpData2" type="application/json">
|
|
{{ src_ip_dict2|safe }}
|
|
</script>
|
|
|
|
<script>
|
|
google.charts.load("current", { packages: ["corechart"] });
|
|
google.charts.setOnLoadCallback(drawChart);
|
|
|
|
function drawChart() {
|
|
// Fetch and parse the JSON data from the script tag
|
|
console.log("xd");
|
|
var ddos_data = document.getElementById('srcIpData2').textContent;
|
|
ddos_data = ddos_data.replace(/'/g, '"');
|
|
|
|
|
|
var srcIpDict = JSON.parse(ddos_data);
|
|
// Check if srcIpDict is empty
|
|
if (Object.keys(srcIpDict).length === 0) {
|
|
// If empty, show a message
|
|
document.getElementById("barchart_attack").innerHTML = "<h2 >No attack/threat</h2>";
|
|
return; // Exit the function early
|
|
}
|
|
|
|
function getChartData() {
|
|
var data = [["Source IP", "Count", { role: "style" }]];
|
|
|
|
// Iterate over the srcIpDict and push the IPs and their counts into the data array
|
|
for (var ip in srcIpDict) {
|
|
if (srcIpDict.hasOwnProperty(ip)) {
|
|
data.push([ip, srcIpDict[ip], "#1E51C7"]); // Color can be changed as needed
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
function drawDynamicChart() {
|
|
var data = google.visualization.arrayToDataTable(getChartData());
|
|
|
|
var view = new google.visualization.DataView(data);
|
|
view.setColumns([0, 1,
|
|
{
|
|
calc: "stringify",
|
|
sourceColumn: 1,
|
|
type: "string",
|
|
role: "annotation"
|
|
},
|
|
2
|
|
]);
|
|
|
|
var options = {
|
|
title: "Number of Attack Request",
|
|
bar: { groupWidth: "95%" },
|
|
legend: { position: "none" },
|
|
backgroundColor: '#0c212b',
|
|
tooltip: { trigger: 'none' },
|
|
hAxis: {
|
|
viewWindow: {
|
|
min: 0,
|
|
max: 15 // Adjust the max dynamically
|
|
}
|
|
}
|
|
};
|
|
|
|
var chart = new google.visualization.BarChart(document.getElementById("barchart_attack"));
|
|
chart.draw(view, options);
|
|
}
|
|
drawDynamicChart();
|
|
}
|
|
|
|
|
|
// Initial draw
|
|
|
|
</script>
|
|
|
|
<script type="application/json" id="ddos-sums2">{{ ddos_sums|safe }}</script>
|
|
<script type="text/javascript">
|
|
google.charts.load("current", { packages: ['corechart'] });
|
|
google.charts.setOnLoadCallback(drawChart);
|
|
|
|
function drawChart() {
|
|
|
|
// Fetch the DDoS data from the application/json script tag
|
|
ddos_data = document.getElementById('ddos-sums2').textContent;
|
|
ddos_data = ddos_data.replace(/'/g, '"');
|
|
console.log(ddos_data);
|
|
var ddosData = JSON.parse(ddos_data)
|
|
|
|
// Prepare the data for Google Charts
|
|
var data = google.visualization.arrayToDataTable([
|
|
["Element", "Density", { role: "style" }],
|
|
["Transmitted Packets", ddosData['pktcount'], "#1EBBC7"],
|
|
// ["byteperflow", ddosData['byteperflow'], "#1E51C7"],
|
|
// ["tot_kbps", ddosData['tot_kbps'], "#1D86C7"],
|
|
// ["rx_kbps", ddosData['rx_kbps'], "#1EC79A"],
|
|
// ["flows", ddosData['flows'], "#201EC7"],
|
|
// ["bytecount", ddosData['bytecount'], "#54A3A8"],
|
|
// ["tot_dur", ddosData['tot_dur'], "#546DA8"]
|
|
]);
|
|
|
|
var view = new google.visualization.DataView(data);
|
|
view.setColumns([0, 1, 2]);
|
|
|
|
var options = {
|
|
title: "Transmitted Packets",
|
|
bar: { groupWidth: "15%" },
|
|
legend: { position: "none" },
|
|
backgroundColor: '#0c212b',
|
|
tooltip: { trigger: 'none' },
|
|
vAxis: {
|
|
title: 'Count',
|
|
viewWindow: {
|
|
min: 0,
|
|
max: 3000
|
|
}
|
|
}
|
|
};
|
|
|
|
// Draw the chart in the specified div
|
|
var chart = new google.visualization.ColumnChart(document.getElementById("TransmittedChart"));
|
|
chart.draw(view, options);
|
|
}
|
|
</script>
|
|
<script type="application/json" id="ddos-sums3">{{ ddos_sums|safe }}</script>
|
|
<script type="text/javascript">
|
|
google.charts.load("current", { packages: ['corechart'] });
|
|
google.charts.setOnLoadCallback(drawChart);
|
|
|
|
function drawChart() {
|
|
|
|
// Fetch the DDoS data from the application/json script tag
|
|
ddos_data = document.getElementById('ddos-sums3').textContent;
|
|
ddos_data = ddos_data.replace(/'/g, '"');
|
|
console.log(ddos_data);
|
|
var ddosData = JSON.parse(ddos_data)
|
|
|
|
// Prepare the data for Google Charts
|
|
var data = google.visualization.arrayToDataTable([
|
|
["Element", "Density", { role: "style" }],
|
|
// ["pktcount", ddosData['pktcount'], "#54A3A8"],
|
|
["Transmitted Bytes", ddosData['bytecount'], "#54A3A8"],
|
|
// ["byteperflow", ddosData['byteperflow'], "#1E51C7"],
|
|
// ["tot_kbps", ddosData['tot_kbps'], "#1D86C7"],
|
|
// ["rx_kbps", ddosData['rx_kbps'], "#1EC79A"],
|
|
// ["flows", ddosData['flows'], "#201EC7"],
|
|
// ["tot_dur", ddosData['tot_dur'], "#546DA8"]
|
|
]);
|
|
|
|
var view = new google.visualization.DataView(data);
|
|
view.setColumns([0, 1, 2]);
|
|
|
|
var options = {
|
|
title: "Transmitted Bytes",
|
|
bar: { groupWidth: "15%" },
|
|
legend: { position: "none" },
|
|
backgroundColor: '#0c212b',
|
|
tooltip: { trigger: 'none' },
|
|
vAxis: {
|
|
title: 'Count',
|
|
viewWindow: {
|
|
min: 0,
|
|
max: 3000
|
|
}
|
|
}
|
|
};
|
|
|
|
// Draw the chart in the specified div
|
|
var chart = new google.visualization.ColumnChart(document.getElementById("TransmittedBytesChart"));
|
|
chart.draw(view, options);
|
|
}
|
|
</script>
|
|
|
|
<!-- <script src="{% static 'ddos/js/columnChart.js'%}"></script> -->
|
|
<!-- <script src="{% static 'ddos/js/barChart.js'%}"></script> -->
|
|
<!-- <script src="{% static 'ddos/js/barchartAttack.js'%}"></script> -->
|
|
<!-- <script src="{% static 'ddos/js/StackedBarCharts.js'%}"></script> -->
|
|
<!-- <script src="{% static 'ddos/js/StackedColumnsChart.js'%}"></script> -->
|
|
<!-- <script src="{% static 'ddos/js/DurationChart.js'%}"></script> -->
|
|
<!-- <script src="{% static 'ddos/js/TransmittedChart.js'%}"></script> -->
|
|
<!-- <script src="{% static 'ddos/js/TransmittedBytesChart.js'%}"></script> -->
|
|
<!-- <script src="{% static 'ddos/js/SwitchChart.js'%}"></script> -->
|
|
<script src="{% static 'ddos/js/LineChart.js'%}"></script>
|
|
<script src="{% static 'ddos/js/PieSliceChart.js'%}"></script>
|
|
<script src="{% static 'ddos/js/LineColumnsChart.js'%}"></script>
|
|
<script src="{% static 'ddos/js/LineFlowDurationChart.js'%}"></script>
|
|
<script src="{% static 'ddos/js/columnInThreeChart.js'%}"></script>
|
|
<script src="{% static 'ddos/js/columnInHTTPChart.js'%}"></script>
|
|
<script src="{% static 'ddos/js/ScatterDDoSPCAChart.js'%}"></script>
|
|
<script src="{% static 'ddos/js/index.js'%}"></script>
|
|
</body>
|
|
{% endblock %}
|
|
</html>ype="application/json" id="protocolData">
|
|
{{ protocol_counts | safe }}
|
|
</script>
|