let series = {}; let names = []; let statsresult = new Promise(function (resolve, reject) { $.ajax({ url: "https://ipssignatures.appspot.com/api/stats", dataType: "json", error: () => reject('API Call Failed.'), success: function (result) { resolve(result) }, }); }); let pageSize = 1000; // 1000 is max. let listresult = new Promise(function (resolve, reject) { let ajx = function (pageIndex) { $.ajax({ url: "https://ipssignatures.appspot.com/api/list?any=true&pageSize=" + pageSize + "&pageIndex=" + pageIndex, dataType: "json", error: () => { reject('API Call Failed.'); alert('API Call Failed.') }, success: function (result) { for (let row of result.data) { let cve = row.cve; let pds = row.publishedDate; let ymd = pds.split('-'); let pd = new Date(ymd[0], ymd[1] - 1, ymd[2]); for (let name in row) { let link = row[name].link; if (link && typeof link !== 'function') { let ds = row[name].date; if (ds !== 'unknown') { ymd = ds.split('-'); let d = new Date(ymd[0], ymd[1] - 1, ymd[2]); let delay = Math.ceil((d - pd) / 86400000); if (delay > -250) { if (!series[name]) { series[name] = {}; } let pddelay = pd.toDateString() + delay; if (!series[name][pddelay]) { series[name][pddelay] = { pd: pd, delay: delay, cve: cve, count: 1 } } else { let oldcve = series[name][pddelay].cve; let oldcount = series[name][pddelay].count; if (oldcount < 10) { series[name][pddelay].cve = oldcve + "\n" + cve; } else if (oldcount === 10) { series[name][pddelay].cve = oldcve + "\n" + 'and more'; } series[name][pddelay].count = oldcount + 1; } } } } } } names = []; for (let name in series) { names.push(name); } let maxs = {}; for (let name in series) { let max = 0; for (let pddelay in series[name]) { if (series[name][pddelay].count > max) { max = series[name][pddelay].count; } } maxs[name] = max; } names.sort((a, b) => maxs[b] - maxs[a]); resolve(); if (result.data.length === pageSize) { let nextPage = pageIndex + 1; ajx(nextPage); } if (pageIndex !== 1) { drawScatterChart(); } } }) } ajx(1); }); google.charts.load('current', { 'packages': ['corechart'] }); google.charts.setOnLoadCallback(drawScatterChart); google.charts.setOnLoadCallback(drawColumnChart); async function drawColumnChart() { let counter = []; let r = { min: 0, max: 0, count: {}, range: 1, }; counter.push(r); for (let i = 1; i < 10; i++) { r = JSON.parse(JSON.stringify(r)); r.min = i; r.max = i; counter.push(r); r = JSON.parse(JSON.stringify(r)); r.min = -i; r.max = -i; counter.push(r); } for (let i = 10; i < 100; i = i + 10) { r = JSON.parse(JSON.stringify(r)); r.min = i; r.max = i + 9; r.range = r.max - r.min + 1; counter.push(r); r = JSON.parse(JSON.stringify(r)); [r.min, r.max] = [-r.max, -r.min]; counter.push(r); } for (let i = 100; i < 10000; i = i * 10) { r = JSON.parse(JSON.stringify(r)); r.min = i; r.max = i * 10 - 1; r.range = r.max - r.min + 1; counter.push(r); r = JSON.parse(JSON.stringify(r)); [r.min, r.max] = [-r.max, -r.min]; counter.push(r); } counter.sort((a, b) => a.min - b.min); let result; try { result = await statsresult; } catch (err) { alert(err); return; } let data = new google.visualization.DataTable(); data.addColumn('string', 'delay'); let min = 100000; let max = -100000; for (let name in result.delay) { data.addColumn('number', name); let delays = result.delay[name]; for (let d in delays) { let n = parseInt(delays[d]); let delay = parseInt(d); if (delay < min) { min = delay; } if (delay > max) { max = delay; } for (let r of counter) { if (delay >= r.min && delay <= r.max) { if (r.count[name]) { r.count[name] += n; } else { r.count[name] = n; } } } } } for (let r of counter) { let row = []; if (r.min === r.max) { row.push(r.min + ""); } else { row.push(r.min + " - " + r.max); } for (let name in result.delay) { let n = r.count[name]; if (n === undefined) { n = 0; } row.push(n / r.range); } data.addRow(row); } let options = { title: 'Distribution of Signitures', hAxis: { title: 'Delay from the Published Date by NIST (days) ', showTextEvery: 1, slantedText: true, slantedTextAngle: 70 }, vAxis: { title: 'Number of signatures / Number of range' }, bar: { groupWidth: "65%" }, isStacked: true, }; let columndiv = document.getElementById("column_div"); let chart = new google.visualization.ColumnChart(columndiv); let x = document.body.scrollWidth; let chartWidth = x - (3 * 2); if (chartWidth > 600) { columndiv.setAttribute("style", "width : " + chartWidth + "px;" + "height : " + chartWidth / 2 + "px;") } chart.draw(data, options); } async function drawScatterChart() { try { await listresult; } catch (err) { return; } let data = new google.visualization.DataTable(); data.addColumn('date', 'Published Date by NIST'); for (let name of names) { data.addColumn('number', name); data.addColumn({ type: 'string', role: 'tooltip' }); data.addColumn({ type: 'string', role: 'style' }); } for (let name of names) { for (let pddelay in series[name]) { let row = []; let r = series[name][pddelay]; row.push(r.pd); for (let _name of names) { if (name === _name) { row.push(r.delay); row.push(name + "\n" + r.cve); let d = Math.sqrt(r.count); row.push(`point {size:${d * 5}}`); } else { row.push(null); row.push(null); row.push(null); } } data.addRow(row); } } let options = { title: 'Delay from the Published Date by NIST', hAxis: { title: 'Published Date by NIST' }, vAxis: { title: 'Delay (days)' }, dataOpacity: 0.5, }; let scatterdiv = document.getElementById('scatter_div'); let chart = new google.visualization.ScatterChart(scatterdiv); let x = document.body.scrollWidth; let chartWidth = x - (3 * 2); if (chartWidth > 600) { scatterdiv.setAttribute("style", "width : " + chartWidth + "px;" + "height : " + chartWidth / 2 + "px;") } chart.draw(data, options); }