1(function() { 2 'use strict'; 3 4 let diameter = 1280; 5 let radius = diameter / 2; 6 let innerRadius = radius - 240; 7 8 let cluster = d3.cluster(); 9 cluster.size([ 360, innerRadius ]); 10 11 let line = d3.radialLine(); 12 line.curve(d3.curveBundle.beta(0.85)); 13 line.radius(function(d) { return d.y; }); 14 line.angle(function(d) { return d.x / 180 * Math.PI; }); 15 16 let link; 17 let node; 18 let selectedNode; 19 let selectedSubNode; 20 21 function init() { 22 let domListCol = document.createElement("div"); 23 domListCol.id = "violate_list_column"; 24 let domGraphCol = document.createElement("div"); 25 domGraphCol.id = "dep_graph_column"; 26 let domResetBtn = document.createElement("button"); 27 domResetBtn.id = "reset_btn"; 28 domResetBtn.innerHTML = "Reset"; 29 domGraphCol.appendChild(domResetBtn); 30 31 document.body.appendChild(domListCol); 32 document.body.appendChild(domGraphCol); 33 34 let canvas = d3.select("#dep_graph_column").append("svg"); 35 canvas.attr("width", diameter + 200); 36 canvas.attr("height", diameter); 37 38 let svg = canvas.append("g"); 39 svg.attr("transform", "translate(" + (radius + 100) + "," + radius + ")"); 40 41 link = svg.append("g").selectAll(".link"); 42 node = svg.append("g").selectAll(".node"); 43 44 showResult(depData, violatedLibs); 45 } 46 47 function showList(depMap, violatedLibs) { 48 function makeTitle(tagName) { 49 let domTitle = document.createElement("div"); 50 let domText = document.createElement("h3"); 51 domText.innerHTML = tagName; 52 domTitle.appendChild(domText); 53 return domTitle; 54 } 55 function makeButton(libName, count) { 56 let domButton = document.createElement("button"); 57 domButton.className = "violate"; 58 domButton.innerHTML = libName + " (" + count + ")"; 59 domButton.onclick = function() { 60 this.classList.toggle("active"); 61 let currentList = this.nextElementSibling; 62 if (currentList.style.display === "block") { 63 currentList.style.display = "none"; 64 selectedNode = undefined; 65 if (selectedSubNode) { 66 selectedSubNode.classList.toggle("active"); 67 selectedSubNode.nextElementSibling.style.display = "none"; 68 selectedSubNode = undefined; 69 } 70 resetclicked(); 71 } else { 72 currentList.style.display = "block"; 73 for (let i = 1; i < currentList.childElementCount; i += 2) { 74 currentList.childNodes[i].style.display = "none"; 75 } 76 if (selectedNode) { 77 selectedNode.classList.toggle("active"); 78 selectedNode.nextElementSibling.style.display = "none"; 79 if (selectedSubNode) { 80 selectedSubNode.classList.toggle("active"); 81 selectedSubNode.nextElementSibling.style.display = "none"; 82 selectedSubNode = undefined; 83 } 84 } 85 selectedNode = domButton; 86 mouseclicked(depMap[libName]); 87 } 88 }; 89 return domButton; 90 } 91 function makeSubButton(libName, count) { 92 let domButton = document.createElement("button"); 93 domButton.className = "violate-list"; 94 domButton.innerHTML = libName + " (" + count + ")"; 95 domButton.onclick = function() { 96 this.classList.toggle("active"); 97 let currentSubList = this.nextElementSibling; 98 if (currentSubList.style.display === "block") { 99 currentSubList.style.display = "none"; 100 selectedSubNode = undefined; 101 } else { 102 currentSubList.style.display = "block"; 103 for (let i = 0; i < currentSubList.childElementCount; i++) { 104 if (currentSubList.childNodes[i].childElementCount > 0) { 105 currentSubList.childNodes[i].childNodes[1].style.display = "none"; 106 } 107 } 108 if (selectedSubNode) { 109 selectedSubNode.classList.toggle("active"); 110 selectedSubNode.nextElementSibling.style.display = "none"; 111 } 112 selectedSubNode = domButton; 113 } 114 }; 115 return domButton; 116 } 117 function changeFormat(symbol) { 118 let res = ""; 119 let i; 120 for (i = 0; i < symbol.length; i++) { 121 if (symbol.charAt(i) >= '0' && symbol.charAt(i) <= '9') { 122 break; 123 } 124 } 125 while (i < symbol.length) { 126 if (symbol.charAt(i) < '0' || symbol.charAt(i) > '9') { 127 break; 128 } 129 let len = parseInt(symbol.substr(i, symbol.length)); 130 let count = 1; 131 if (len < 10) { 132 count = 0; 133 } 134 res = res + "::" + symbol.substr(i + 1 + count, len); 135 i = i + 1 + count + len; 136 } 137 return res.substr(2, res.length); 138 } 139 function makeList(domList, list) 140 { 141 for (let i = 0; i < list.length; i++) { 142 domList.appendChild(makeButton(list[i][0], list[i][1])); 143 let domDepList = document.createElement("div"); 144 let depItem = depMap[list[i][0]]; 145 let violates = depItem.data.violates; 146 for (let j = 0; j < violates.length; j++) { 147 let domDepLib = document.createElement("div"); 148 let tag = depMap[violates[j][0]].data.tag; 149 let symbols = violates[j][1]; 150 let domDepButton = makeSubButton(violates[j][0] + " [" 151 + tag.substring(tag.lastIndexOf(".") + 1) + "]", symbols.length); 152 for (let k = 0; k < symbols.length; k++) { 153 let domDepSym = document.createElement("div"); 154 domDepSym.className = "violate-list-sym"; 155 domDepSym.innerHTML = symbols[k]; 156 if (symbols[k].indexOf("_Z") === 0) { 157 let cplusplusSym = document.createElement("span"); 158 cplusplusSym.className = "cplusplus-sym"; 159 cplusplusSym.innerHTML = 160 changeFormat(symbols[k].substr(2, symbols[k].length)); 161 domDepSym.appendChild(cplusplusSym); 162 domDepSym.onmouseover = function(e) { 163 e.currentTarget.style.position = "relative"; 164 e.currentTarget.childNodes[1].style.display = "block"; 165 }; 166 domDepSym.onmouseout = function(e) { 167 e.currentTarget.style.position = "static"; 168 e.currentTarget.childNodes[1].style.display = "none"; 169 }; 170 } 171 domDepLib.appendChild(domDepSym); 172 } 173 domDepList.appendChild(domDepButton); 174 domDepList.appendChild(domDepLib); 175 } 176 domList.appendChild(domDepList); 177 domDepList.style.display = "none"; 178 } 179 } 180 181 let domViolatedList = document.getElementById("violate_list_column"); 182 if ("vendor.private.bin" in violatedLibs) { 183 let list = violatedLibs["vendor.private.bin"]; 184 domViolatedList.appendChild(makeTitle("VENDOR (" + list.length + ")")); 185 makeList(domViolatedList, list); 186 } 187 for (let tag in violatedLibs) { 188 if (tag === "vendor.private.bin") 189 continue; 190 let list = violatedLibs[tag]; 191 if (tag === "system.private.bin") 192 tag = "SYSTEM"; 193 else 194 tag = tag.substring(tag.lastIndexOf(".") + 1).toUpperCase(); 195 domViolatedList.appendChild(makeTitle(tag + " (" + list.length + ")")); 196 makeList(domViolatedList, list); 197 } 198 } 199 200 function showResult(depDumps, violatedLibs) { 201 let root = tagHierarchy(depDumps).sum(function(d) { return 1; }); 202 cluster(root); 203 204 let libsDepData = libsDepends(root.leaves()); 205 showList(libsDepData[1], violatedLibs); 206 link = link.data(libsDepData[0]) 207 .enter() 208 .append("path") 209 .each(function(d) { d.source = d[0], d.target = d[d.length - 1]; }) 210 .attr("class", function(d) { return d.allow ? "link" : "link--violate" }) 211 .attr("d", line); 212 213 node = node.data(root.leaves()) 214 .enter() 215 .append("text") 216 .attr("class", 217 function(d) { 218 return d.data.parent.parent.parent.key == "system" ? 219 (d.data.parent.parent.key == "system.public" ? 220 "node--sys-pub" : 221 "node--sys-pri") : 222 "node"; 223 }) 224 .attr("dy", "0.31em") 225 .attr("transform", 226 function(d) { 227 return "rotate(" + (d.x - 90) + ")translate(" + (d.y + 8) + ",0)" + 228 (d.x < 180 ? "" : "rotate(180)"); 229 }) 230 .attr("text-anchor", function(d) { return d.x < 180 ? "start" : "end"; }) 231 .text(function(d) { return d.data.key; }) 232 .on("click", mouseclicked); 233 document.getElementById("reset_btn").onclick = resetclicked; 234 } 235 236 function resetclicked() { 237 if (selectedNode) { 238 selectedNode.classList.toggle("active"); 239 selectedNode.nextElementSibling.style.display = "none"; 240 if (selectedSubNode) { 241 selectedSubNode.classList.toggle("active"); 242 selectedSubNode.nextElementSibling.style.display = "none"; 243 selectedSubNode = undefined; 244 } 245 selectedNode = undefined; 246 } 247 link.classed("link--target", false) 248 .classed("link--source", false); 249 node.classed("node--target", false) 250 .classed("node--source", false) 251 .classed("node--selected", false); 252 } 253 254 function mouseclicked(d) { 255 node.each(function(n) { n.target = n.source = false; }); 256 257 link.classed("link--target", 258 function(l) { 259 if (l.target === d) { 260 l.source.source = true; 261 return true; 262 } else { 263 return false; 264 } 265 }) 266 .classed("link--source", 267 function(l) { 268 if (l.source === d) { 269 l.target.target = true; 270 return true; 271 } else { 272 return false; 273 } 274 }) 275 .filter(function(l) { return l.target === d || l.source === d; }) 276 .raise(); 277 278 node.classed("node--target", 279 function(n) { 280 return n.target; 281 }) 282 .classed("node--source", 283 function(n) { return n.source; }) 284 .classed("node--selected", 285 function(n) { 286 return n === d; 287 }); 288 } 289 290 function tagHierarchy(depDumps) { 291 let map = {}; 292 293 function find(name, tag, data) { 294 let node = map[name], i; 295 if (!node) { 296 node = map[name] = data || { name : name, children : [] }; 297 if (name.length) { 298 node.parent = find(tag, tag.substring(0, tag.lastIndexOf("."))); 299 node.parent.children.push(node); 300 node.key = name; 301 } 302 } 303 return node; 304 } 305 306 depDumps.forEach(function(d) { find(d.name, d.tag, d); }); 307 308 return d3.hierarchy(map[""]); 309 } 310 311 function libsDepends(nodes) { 312 let map = {}, depends = []; 313 314 // Compute a map from name to node. 315 nodes.forEach(function(d) { map[d.data.name] = d; }); 316 317 // For each dep, construct a link from the source to target node. 318 nodes.forEach(function(d) { 319 if (d.data.depends) 320 d.data.depends.forEach(function(i) { 321 let l = map[d.data.name].path(map[i]); 322 l.allow = true; 323 depends.push(l); 324 }); 325 if (d.data.violates.length) { 326 map[d.data.name].not_allow = true; 327 d.data.violates.forEach(function(i) { 328 map[i[0]].not_allow = true; 329 let l = map[d.data.name].path(map[i[0]]); 330 l.allow = false; 331 depends.push(l); 332 }); 333 } 334 }); 335 336 return [ depends, map ]; 337 } 338 339 window.onload = init; 340})(); 341