├── README.md ├── china.css ├── china.html ├── china.js ├── data ├── china_cities.csv ├── china_cities.json ├── china_provinces.json ├── country-codes.csv └── readme-world.json ├── flags.css ├── fonts.css ├── fonts └── Norse-Mapcons.woff ├── images ├── DarkNoiseBackground.png ├── flags │ └── flags16.png ├── loading.gif ├── norse-white.png └── unknown-poly.png ├── index.html ├── ipviking.css ├── ipviking.js ├── nodejs └── main.js └── presentations.js /README.md: -------------------------------------------------------------------------------- 1 | livemapdemo 2 | =========== 3 | 4 | 地图实时攻击演示 5 | 6 | 7 | 8 | 目前包含: 9 | * 世界地图 10 | 基本就是copy了ipviking的展示,我觉得他们做的已经非常满足我的需求了。 11 | 12 | * 中国地图 13 | 目前只是简单的进行了修改,能够显示中国地图,但是显示的数据不能对应到城市或者省份,以后有时间再改。 14 | 15 | 16 | 服务端运行: 17 | nodejs目录下,npm install mysql,nodejs-websocket,geoip-lite,underscore 18 | 自行填充实时数据。 19 | 20 | 网页文件直接访问index.html查看世界地图,china.html查看中国地图 21 | -------------------------------------------------------------------------------- /china.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800); 2 | @import url(http://fonts.googleapis.com/css?family=Oswald:400,300,700); 3 | 4 | body { 5 | overflow: hidden; 6 | margin: 0; 7 | color: white; 8 | background: url(images/DarkNoiseBackground.png); 9 | font-family: "Oswald", "Open Sans", sans-serif; 10 | } 11 | 12 | ol { 13 | list-style-type: none; 14 | margin-left: -2.0em; 15 | } 16 | 17 | td { 18 | font-family: "Open Sans", "Oswald", sans-serif; 19 | font-weight: 400; 20 | } 21 | 22 | 23 | th { 24 | font-weight: normal; 25 | } 26 | 27 | h1, h2, h3, h4 { 28 | font-family: "Oswald", "Open Sans", sans-serif; 29 | } 30 | 31 | #drawer { 32 | position: absolute; 33 | top: 48px; 34 | right: 6px; 35 | z-index: 100; 36 | height: 385px; 37 | width: 595px; 38 | } 39 | 40 | .blue-bg { 41 | background: rgb(0, 78, 176); 42 | background: transparent\9; 43 | background-color: rgb(0, 78, 176, 0.95); 44 | border-radius: 4px; 45 | border: 1px solid rgba(0, 78, 176); 46 | border: 1px solid rgba(0, 78, 176, 0.95); 47 | -webkit-background-clip: padding-box; /* for Safari */ 48 | background-clip: padding-box; /* for IE9+, Firefox 4+, Opera, Chrome */ 49 | } 50 | 51 | #drawer-content { 52 | height: 100%; 53 | float: right; 54 | overflow: hidden; 55 | } 56 | 57 | #drawer-inner a, 58 | #drawer-content.info-btn { 59 | text-decoration: underline; 60 | color: #fff; 61 | } 62 | 63 | #drawer-inner a:hover, 64 | #drawer-content .info-btn:hover { 65 | color: rgb(20, 180, 255); 66 | } 67 | 68 | #drawer-inner { 69 | padding: 0 1em; 70 | font-size: 11px; 71 | font-family: "Open Sans", "Oswald", sans-serif; 72 | font-weight: 300; 73 | line-height: 13px; 74 | } 75 | 76 | #drawer-content h1 { 77 | margin-top: 5px; 78 | font-size: 24px; 79 | font-family: "Open Sans", "Oswald", sans-serif; 80 | font-weight: 300; 81 | line-height: 30px; 82 | } 83 | 84 | #drawer-left { 85 | float: left; 86 | width: 60%; 87 | } 88 | 89 | .table-ref { 90 | font-family: "Oswald", "Open Sans"; 91 | font-weight: bold; 92 | text-transform: uppercase; 93 | font-size: 0.9em; 94 | } 95 | 96 | /* 97 | This has awful performance... 98 | #drawer-content .footer { 99 | width: 480px; 100 | position: absolute; 101 | bottom: 0; 102 | } 103 | */ 104 | 105 | nav { 106 | /* background-color: rgba(0, 140, 240, 0.95);*/ 107 | background: linear-gradient(rgba(0, 138, 255, 0.5), 108 | rgba(0, 150, 255, 0.5)), 109 | rgba(0, 0, 0, 0.8); 110 | float: left; 111 | width: 40px; 112 | border-bottom-left-radius: 6px; 113 | } 114 | 115 | nav ul { 116 | list-style-type: none; 117 | margin: 0 0 0 -2.4em; 118 | } 119 | 120 | nav ul li { 121 | margin: 0.2em; 122 | font-size: 1.4em; 123 | text-align: center; 124 | } 125 | 126 | nav ul li a { 127 | display: block; 128 | } 129 | 130 | nav ul li a:visited, a:link { 131 | color: white; 132 | text-decoration: none; 133 | } 134 | 135 | nav ul li a:hover { 136 | color: white; 137 | border-top-color: white; 138 | text-decoration: underline; 139 | } 140 | 141 | #content { 142 | width: 100%; 143 | opacity: 0; 144 | } 145 | 146 | #display-label-container { 147 | width: 100%; 148 | text-align: center; 149 | position: absolute; 150 | z-index: 6; 151 | text-shadow: -1px -1px 0 #000, 152 | 1px -1px 0 #000, 153 | -1px 1px 0 #000, 154 | 1px 1px 0 #000; 155 | } 156 | 157 | #top-line { 158 | width: 100%; 159 | background-color: rgb(1, 73, 128); 160 | height: 5px; 161 | } 162 | 163 | #logo { 164 | position: absolute; 165 | left: 6px; 166 | top: 12px; 167 | z-index: 100; 168 | } 169 | 170 | #loading { 171 | position: absolute; 172 | right: 4em; 173 | bottom: 1em; 174 | } 175 | 176 | #info { 177 | position: absolute; 178 | right: 20em; 179 | top: 1em; 180 | } 181 | 182 | .overlay { 183 | position: absolute; 184 | top: 0; 185 | left: 0; 186 | right: 0; 187 | z-index: 4; 188 | } 189 | 190 | .icon { 191 | width: 1em; 192 | } 193 | 194 | .buffer { 195 | visibility: hidden; 196 | } 197 | 198 | .shadow { 199 | -moz-box-shadow: 0 0 5px 5px rgb(40, 50, 80); 200 | -webkit-box-shadow: 0 0 5px 5px rgb(40, 50, 80); 201 | box-shadow: 0 0 5px 5px rgb(40, 50, 80); 202 | } 203 | 204 | .box { 205 | position: absolute; 206 | z-index: 20; 207 | 1px -1px 0 #000, 208 | -1px 1px 0 #000, 209 | 1px 1px 0 #000; 210 | } 211 | 212 | .gray-bg { 213 | background: rgb(51,51,51); 214 | background: transparent\9; 215 | background: rgba(51,51,51,0.5); 216 | border-radius: 4px; 217 | border: 1px solid rgba(51, 51, 51); 218 | border: 1px solid rgba(51, 51, 51, 0.5); 219 | -webkit-background-clip: padding-box; /* for Safari */ 220 | background-clip: padding-box; /* for IE9+, Firefox 4+, Opera, Chrome */ 221 | } 222 | 223 | .black-solid { 224 | background-color: rgba(10, 20, 30, 0.8); 225 | border: thin solid rgb(0, 180, 240); 226 | border-bottom-right-radius: 6px; 227 | border-bottom-left-radius: 6px; 228 | -webkit-box-shadow: 0 0 3px 1px rgb(0, 120, 240); 229 | -moz-box-shadow: 0 0 3px 1px rgb(0, 120, 240); 230 | box-shadow: 0 0 3px 1px rgb(0, 120, 240); 231 | } 232 | 233 | .table-container { 234 | z-index: -2; 235 | } 236 | 237 | /* 238 | .data table th { 239 | color: rgb(45, 255, 254); 240 | } 241 | */ 242 | 243 | .data { 244 | width: 180px; 245 | } 246 | 247 | .data table tr { 248 | line-height: 18px; 249 | text-align: left; 250 | } 251 | 252 | .data table td, 253 | .data table th { 254 | font-size: 12px; 255 | } 256 | 257 | .data table th { 258 | font-size: 13px; 259 | font-family: "Open Sans Bold", "Oswald", sans-serif; 260 | font-weight: 700; 261 | text-transform: uppercase; 262 | } 263 | 264 | .data table th [class^="icon-"], .data table th [class*=" icon-"] { 265 | font-size: 16px; 266 | } 267 | 268 | .data table td span.numeric { 269 | font-size: 10px; 270 | font-family: "Open Sans Light", "Oswald", sans-serif; 271 | font-weight: 300; 272 | } 273 | 274 | .data .flag { 275 | margin-right: 20px; 276 | height: 1.0em; 277 | } 278 | 279 | .data .numeric { 280 | margin-right: 10px; 281 | } 282 | 283 | .data .icon-number { 284 | margin-right: 8px; 285 | } 286 | 287 | .data colgroup .bar-col { width: 0; } 288 | .data colgroup .total-count { width: 2.6em; } 289 | .data colgroup .data-label-small { width: 1.6em; } 290 | .data colgroup .data-label { width: 10em; } 291 | .data colgroup .port-label { width: 2.8em; } 292 | 293 | 294 | .data tr.row:hover { 295 | background-color: #0c2b4a; 296 | } 297 | 298 | .data table .bar { 299 | position: absolute; 300 | height: 20px; 301 | margin-top: -10px; 302 | background-color: #0c2b4a; 303 | z-index: -1; 304 | border-radius: 3px; 305 | max-width: 98%; 306 | } 307 | 308 | .data table tr td:nth-child(2), 309 | .data table tr th:nth-child(2) { 310 | text-align: right; 311 | padding-right: 0.4em; 312 | } 313 | 314 | .port-circle { 315 | font-size: 1.8em; 316 | text-align: center; 317 | line-height: 0.5em; 318 | } 319 | 320 | .table-header { 321 | text-align: center; 322 | color: rgb(40, 255, 255); 323 | color: rgb(255, 255, 255); 324 | text-transform: uppercase; 325 | border-top-right-radius: 6px; 326 | border-top-left-radius: 6px; 327 | margin-bottom: 4px; 328 | } 329 | 330 | .table-header h1 { 331 | margin: 0.4em 0.8em; 332 | font-family: "Open Sans", "Oswald", sans-serif; 333 | font-weight: 400; 334 | font-size: 16px; 335 | text-align: left; 336 | } 337 | 338 | .top-left { 339 | top: 72px; 340 | left: 6px; 341 | } 342 | 343 | .bottom { 344 | bottom: 6px; 345 | } 346 | 347 | .top-right { 348 | right: 6px; 349 | top: 48px; 350 | } 351 | 352 | .bottom-right { 353 | bottom: 50px; 354 | right: 6px; 355 | } 356 | 357 | .info-controls { 358 | position: absolute; 359 | top: 6px; 360 | right: 6px; 361 | z-index: 20; 362 | } 363 | 364 | .info-controls .icon-close { 365 | font-size: 14px; 366 | } 367 | 368 | .info-controls > div { 369 | float: right; 370 | width: 86px; 371 | height: 34px; 372 | } 373 | 374 | .info-controls > div:first-child { 375 | margin-left: 6px; 376 | } 377 | 378 | .controls { 379 | display: block; 380 | text-align: center; 381 | list-style: none; 382 | padding: 0; 383 | margin: 0; 384 | } 385 | 386 | .controls:hover { 387 | color: #00a6ff; 388 | cursor: pointer; 389 | } 390 | 391 | .controls > span { 392 | display: inline-block; 393 | line-height: 34px; 394 | } 395 | 396 | .information { 397 | display: block; 398 | text-align: center; 399 | list-style: none; 400 | padding: 0; 401 | margin: 0; 402 | } 403 | 404 | .information:hover { 405 | color: #00a6ff; 406 | cursor: pointer; 407 | } 408 | 409 | .information > span { 410 | line-height: 34px; 411 | display: inline-block; 412 | } 413 | 414 | .world { 415 | stroke: #555; 416 | stroke-linejoin: round; 417 | } 418 | 419 | .tick { 420 | stroke: white; 421 | } 422 | 423 | /* The data console */ 424 | #console { 425 | left: 6px; 426 | bottom: 32px; 427 | pointer-events: none; 428 | padding: 6px 12px; 429 | } 430 | 431 | #console .table-header h1 { 432 | margin: 0; 433 | min-width: 156px; 434 | } 435 | 436 | #console .table-header { 437 | margin-bottom: 0; 438 | } 439 | 440 | #console table { 441 | font-size: 10px; 442 | font-family: "Open Sans Normal", "Oswald", sans-serif; 443 | font-weight: 400; 444 | line-height: 12px; 445 | border-collapse: collapse; 446 | } 447 | 448 | #console table td, 449 | #console table th { 450 | text-shadow: none; 451 | padding-right: 20px; 452 | } 453 | 454 | #console table td:last-child, 455 | #console table th:last-child { 456 | padding-right: 0px; 457 | } 458 | 459 | #console table tr.first-level { 460 | font-size: 12px; 461 | font-family: "Open Sans Bold", "Oswald", sans-serif; 462 | font-weight: 700; 463 | line-height: 16px; 464 | text-align: left; 465 | text-transform: uppercase; 466 | } 467 | 468 | #console table tr.second-level { 469 | font-size: 10px; 470 | font-family: "Open Sans Bold", "Oswald", sans-serif; 471 | font-weight: 700; 472 | line-height: 12px; 473 | text-align: left; 474 | padding-bottom: 0.2em; 475 | font-weight: light; 476 | text-transform: uppercase; 477 | } 478 | 479 | #console table tr.second-level th { 480 | font-weight: light !important; 481 | } 482 | 483 | #console colgroup col.left-border { 484 | padding-left: 0.5em; 485 | } 486 | 487 | #console table span.overflow { 488 | display: block; 489 | overflow: hidden; 490 | text-overflow: ellipsis; 491 | height: 1.4em; 492 | } 493 | 494 | #console colgroup col.timestamp-col { width: 11em; } 495 | #console colgroup col.location-col { width: 130px; } 496 | #console colgroup col.attacker-org-col { width: 160px; } 497 | #console colgroup col.attacker-ip-col { width: 98px; } 498 | #console colgroup col.service-col { width: 70px; } 499 | #console colgroup col.port-col { width: 30px; } 500 | 501 | a.toggle { 502 | color: rgb(55, 116, 172); 503 | pointer-events: all; 504 | } 505 | 506 | #rate-graph { 507 | z-index: 20; 508 | position: absolute; 509 | left: 6px; 510 | bottom: 6px; 511 | width: 100%; 512 | height: 20; 513 | } 514 | 515 | #drawer { 516 | display: none; 517 | } 518 | 519 | #drawer .social-media { 520 | list-style: none; 521 | padding: 0; 522 | margin: 0; 523 | } 524 | 525 | #drawer .social-media li { 526 | display: inline-block; 527 | margin-right: 35px; 528 | } 529 | 530 | #drawer .social-media li:last-child { 531 | margin-right: 0px; 532 | } 533 | 534 | #drawer .social-media a { 535 | text-decoration: none; 536 | font-size: 11px; 537 | font-family: "Open Sans Bold", "Oswald", sans-serif; 538 | font-weight: 700; 539 | } 540 | 541 | /* TODO -- sort these */ 542 | .attacker { 543 | color: rgb(214, 39, 40); 544 | } 545 | 546 | .target { 547 | color: rgb(31, 119, 180); 548 | } 549 | 550 | 551 | /* LEGEND */ 552 | 553 | #legend-container { 554 | float: left; 555 | width: 26%; 556 | margin-left: 10%; 557 | margin-top: 52px; 558 | padding-left: 10px; 559 | background: rgb(0,84,190); /* Old browsers */ 560 | background: -moz-linear-gradient(left, rgba(0,84,190,1) 0px, rgba(0,84,190,1) 3px, rgba(0,78,176,1) 3px, rgba(0,78,176,1) 3px, rgba(0,78,176,1) 100%); /* FF3.6+ */ 561 | background: -webkit-gradient(linear, left top, right top, color-stop(0px,rgba(0,84,190,1)), color-stop(3px,rgba(0,84,190,1)), color-stop(3px,rgba(0,78,176,1)), color-stop(3px,rgba(0,78,176,1)), color-stop(100%,rgba(0,78,176,1))); /* Chrome,Safari4+ */ 562 | background: -webkit-linear-gradient(left, rgba(0,84,190,1) 0px,rgba(0,84,190,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 100%); /* Chrome10+,Safari5.1+ */ 563 | background: -o-linear-gradient(left, rgba(0,84,190,1) 0px,rgba(0,84,190,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 100%); /* Opera 11.10+ */ 564 | background: -ms-linear-gradient(left, rgba(0,84,190,1) 0px,rgba(0,84,190,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 100%); /* IE10+ */ 565 | background: linear-gradient(to right, rgba(0,84,190,1) 0px,rgba(0,84,190,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 100%); /* W3C */ 566 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#0054be', endColorstr='#004eb0',GradientType=1 ); /* IE6-9 */ 567 | } 568 | 569 | #legend-container h4 { 570 | margin: 0; 571 | font-size: 9px; 572 | margin-bottom: 20px; 573 | font-family: "Open Sans Bold", "Oswald", sans-serif; 574 | font-weight: 400; 575 | line-height: 11px; 576 | text-align: left; 577 | } 578 | 579 | #legend > div { 580 | margin: auto 0.5%; 581 | text-align: left; 582 | } 583 | 584 | #legend ul { 585 | list-style-type: none; 586 | margin-left: -2em; 587 | } 588 | 589 | #legend .clusters ul > li { 590 | display: inline-block; 591 | margin: auto 0.8em; 592 | } 593 | 594 | #legend .country-colors ul > li { 595 | display: inline-block; 596 | margin: auto 0.2em; 597 | width: 1.2em; 598 | } 599 | 600 | #particle-legend > p { 601 | margin-left: 40px; 602 | } 603 | 604 | #origin-legend > p { 605 | margin-left: 15px; 606 | } 607 | 608 | #country-legend > p { 609 | margin-left: 5px; 610 | } 611 | 612 | #origin-legend p span { 613 | margin-right: 4px; 614 | } 615 | 616 | #origin-legend p .icon-one { 617 | font-size: 20px; 618 | padding-top: 12px; 619 | margin-right: ; 620 | } 621 | 622 | #origin-legend p .icon-ten { 623 | padding-top: 8px; 624 | font-size: 24px; 625 | } 626 | 627 | #origin-legend p .icon-twohundred { 628 | font-size: 32px; 629 | } 630 | 631 | h4 > span { 632 | margin-right: 5px; 633 | float: left; 634 | margin-top: 1px; 635 | } 636 | 637 | h4 > p { 638 | display: inline-block; 639 | width: 85%; 640 | margin: 0px; 641 | } 642 | 643 | #country-legend p [class^="icon-"], #country-legend p [class*=" icon-"] { 644 | font-size: 20px; 645 | } 646 | 647 | footer { 648 | width: 30%; 649 | float: right; 650 | font-size: 8px; 651 | font-family: "Open Sans", "Oswald", sans-serif; 652 | line-height: 10px; 653 | margin-top: 10px; 654 | } 655 | 656 | #events-data tr td:first-child { 657 | white-space: nowrap; 658 | } 659 | 660 | #message-panel { 661 | display: none; 662 | position: absolute; 663 | margin-left: auto; 664 | margin-right: auto; 665 | left: 0; 666 | right: 0; 667 | top: 300px; 668 | width: 600px; 669 | } 670 | 671 | #message-container { 672 | position: relative; 673 | min-height: 100px; 674 | padding: 10px; 675 | text-align: center; 676 | vertical-align: middle; 677 | } 678 | 679 | #message-container span { 680 | display: inline-block; 681 | vertical-align: middle ; 682 | } 683 | 684 | #close-button { 685 | position: absolute; 686 | width: 100px; 687 | left: 250px; 688 | bottom: 20px; 689 | height: 25px; 690 | color: white; 691 | border-radius: 3px; 692 | } 693 | 694 | #social-icons { 695 | position: absolute; 696 | height: 36px; 697 | width: 180px; 698 | bottom: 6px; 699 | right: 6px; 700 | font-size: 20px; 701 | line-height: 36px; 702 | text-align: center; 703 | z-index: 20; 704 | } 705 | 706 | #social-icons ul { 707 | list-style: none; 708 | padding: 0; 709 | margin: 0; 710 | } 711 | 712 | #social-icons li { 713 | display: inline-block; 714 | } 715 | 716 | #social-icons a { 717 | display: inline-block; 718 | cursor: pointer; 719 | } 720 | 721 | #social-icons a:visited { 722 | color: white; 723 | } 724 | 725 | #unknown-icon { 726 | position: absolute; 727 | width: 36px; 728 | height: 36px; 729 | opacity: 0.6; 730 | } 731 | 732 | #tooltip { 733 | border: 1px solid #777; 734 | } 735 | 736 | #tooltip label { 737 | font-style: italic; 738 | font-size: 70%; 739 | display: block; 740 | float: left; 741 | font-weight: bold; 742 | } 743 | 744 | .counties { 745 | fill: none; 746 | stroke: #aaa; 747 | stroke-width: 0.2px; 748 | stroke-linejoin: round; 749 | } 750 | 751 | .states { 752 | fill: none; 753 | stroke: #777; 754 | stroke-width: 1px; 755 | stroke-linejoin: round; 756 | } 757 | 758 | .active { 759 | fill: orange; 760 | } 761 | 762 | .q0 { fill: #ffffff; } 763 | .q1 { fill: #fee5d9; } 764 | .q2 { fill: #fcae91; } 765 | .q3 { fill: #fb6a4a; } 766 | .q4 { fill: #cb181d; } 767 | -------------------------------------------------------------------------------- /china.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Norse - IPViking Live 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

Loading...

14 |
15 |
16 | 17 | 18 | 19 |
20 | 21 |
22 | 23 |
24 |

25 | 26 | 攻击来源 27 |

28 |
29 |
30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
国家
45 |
46 |
47 | 48 |
49 | 50 |
51 |

52 | 53 | 攻击目标 54 |

55 |
56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
国家
72 |
73 |
74 | 75 |
76 | 77 |
78 |

79 | 80 | 攻击类型 81 |

82 |
83 |
84 | 85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
类型
100 |
101 |
102 | 103 |
104 | 105 |
106 |

107 | 108 | 实时攻击 109 |

110 |
111 |
112 |
113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 |
攻击者目标行为
时间位置IP服务器IP服务器位置攻击类型
139 |
140 |
141 |
142 |
143 | 144 |
145 |
146 | 147 |
148 |
149 |
150 | 151 |
152 |
153 | 154 |
155 | 156 |
157 |
158 |
159 |

Norse Dark Intelligence

160 |

161 | Every second, Norse collects and analyzes live threat 162 | intelligence from darknets in hundreds of locations in 163 | over 40 countries. The attacks shown are based on a 164 | small subset of live flows against the Norse honeypot 165 | infrastructure, representing actual worldwide cyber 166 | attacks by bad actors. At a glance, one can see which 167 | countries are aggressors or targets at the moment, using 168 | which type of attacks (services-ports). 169 |

170 | 171 |

172 | Hovering over the Attack Origins, 173 | Attack Targets, or 174 | Attack Types will 175 | highlight just the attacks emanating from that country 176 | or over that service-port respectively. Hovering over 177 | any bubble on the map, will highlight only the attacks 178 | from that location and type. Press s 179 | to toggle table sizes. 180 |

181 | 182 |

183 | Norse exposes its threat intelligence via 184 | high-performance, machine-readable APIs in a variety of 185 | forms. Norse also provides products and solutions that 186 | assist organizations in protecting and mitigating cyber 187 | attacks. 188 |

189 | 190 |

191 | For more information, please contact: 192 | inquiry@norse-corp.com 193 |

194 | 195 | 202 |
203 | 204 |
205 |
206 |

Each particle represents an attack

207 |

208 |
209 |
210 |

Attack origins are grouped into clusters

211 |

212 | 213 | 214 | 215 |

216 |
217 |
218 |

Countries are shaded in as they're attacked

219 |

220 | 221 | 222 | 223 | 224 | 225 |

226 |
227 |
228 | 229 | 243 |
244 |
245 |
246 |
247 |
248 |

Message Dialog

249 |
250 |
251 | 252 | 253 |
254 |
255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | -------------------------------------------------------------------------------- /data/china_cities.csv: -------------------------------------------------------------------------------- 1 | id,name,value 2 | 3415,六安市,0 3 | 3408,安庆市,0 4 | 3411,滁州市,0 5 | 3418,宣城市,0 6 | 3412,阜阳市,0 7 | 3413,宿州市,0 8 | 3410,黄山市,0 9 | 3414,巢湖市,0 10 | 3416,亳州市,0 11 | 3417,池州市,0 12 | 3401,合肥市,0 13 | 3403,蚌埠市,0 14 | 3402,芜湖市,0 15 | 3406,淮北市,0 16 | 3404,淮南市,0 17 | 3405,马鞍山市,0 18 | 3407,铜陵市,0 19 | 8200,澳门,0 20 | 110228,密云县,0 21 | 110116,怀柔区,0 22 | 110111,房山区,0 23 | 110229,延庆县,0 24 | 110109,门头沟区,0 25 | 110114,昌平区,0 26 | 110115,大兴区,1 27 | 110113,顺义区,0 28 | 110117,平谷区,0 29 | 110112,通州区,1 30 | 110105,朝阳区,1 31 | 110108,海淀区,4 32 | 110106,丰台区,1 33 | 110107,石景山区,1 34 | 110102,西城区,1 35 | 110101,东城区,1 36 | 110104,宣武区,0 37 | 110103,崇文区,0 38 | 500242,酉阳土家族苗族自治县,0 39 | 500236,奉节县,0 40 | 500238,巫溪县,0 41 | 500234,开县,0 42 | 500243,彭水苗族土家族自治县,0 43 | 500235,云阳县,0 44 | 500101,万州区,0 45 | 500229,城口县,0 46 | 500116,江津区,0 47 | 500240,石柱土家族自治县,0 48 | 500237,巫山县,0 49 | 500102,涪陵区,0 50 | 500230,丰都县,0 51 | 500232,武隆县,0 52 | 500119,南川区,0 53 | 500241,秀山土家族苗族自治县,0 54 | 500114,黔江区,0 55 | 500117,合川区,0 56 | 500222,綦江县,0 57 | 500233,忠县,0 58 | 500228,梁平县,0 59 | 500113,巴南区,0 60 | 500223,潼南县,0 61 | 500118,永川区,0 62 | 500231,垫江县,0 63 | 500112,渝北区,0 64 | 500115,长寿区,0 65 | 500225,大足县,0 66 | 500224,铜梁县,0 67 | 500226,荣昌县,0 68 | 500227,璧山县,0 69 | 500109,北碚区,0 70 | 500110,万盛区,0 71 | 500107,九龙坡区,0 72 | 500106,沙坪坝区,0 73 | 500108,南岸区,0 74 | 500105,江北区,0 75 | 500104,大渡口区,0 76 | 500111,双桥区,0 77 | 500103,渝中区,0 78 | 3507,南平市,0 79 | 3504,三明市,0 80 | 3508,龙岩市,0 81 | 3509,宁德市,0 82 | 3501,福州市,0 83 | 3506,漳州市,0 84 | 3505,泉州市,0 85 | 3503,莆田市,0 86 | 3502,厦门市,0 87 | 6209,酒泉市,0 88 | 6207,张掖市,0 89 | 6230,甘南藏族自治州,0 90 | 6206,武威市,0 91 | 6212,陇南市,0 92 | 6210,庆阳市,0 93 | 6204,白银市,0 94 | 6211,定西市,0 95 | 6205,天水市,0 96 | 6201,兰州市,0 97 | 6208,平凉市,0 98 | 6229,临夏回族自治州,0 99 | 6203,金昌市,0 100 | 6202,嘉峪关市,0 101 | 4418,清远市,0 102 | 4402,韶关市,0 103 | 4408,湛江市,0 104 | 4414,梅州市,0 105 | 4416,河源市,0 106 | 4412,肇庆市,0 107 | 4413,惠州市,0 108 | 4409,茂名市,0 109 | 4407,江门市,0 110 | 4417,阳江市,0 111 | 4453,云浮市,0 112 | 4401,广州市,0 113 | 4415,汕尾市,0 114 | 4452,揭阳市,0 115 | 4404,珠海市,0 116 | 4406,佛山市,2 117 | 4451,潮州市,0 118 | 4405,汕头市,0 119 | 4403,深圳市,0 120 | 4419,东莞市,0 121 | 4420,中山市,0 122 | 4510,百色市,0 123 | 4512,河池市,0 124 | 4503,桂林市,0 125 | 4501,南宁市,0 126 | 4502,柳州市,0 127 | 4514,崇左市,0 128 | 4513,来宾市,0 129 | 4509,玉林市,0 130 | 4504,梧州市,0 131 | 4511,贺州市,0 132 | 4507,钦州市,0 133 | 4508,贵港市,0 134 | 4506,防城港市,0 135 | 4505,北海市,1 136 | 5203,遵义市,0 137 | 5226,黔东南苗族侗族自治州,0 138 | 5224,毕节地区,0 139 | 5227,黔南布依族苗族自治州,0 140 | 5222,铜仁地区,0 141 | 5223,黔西南布依族苗族自治州,0 142 | 5202,六盘水市,0 143 | 5204,安顺市,0 144 | 5201,贵阳市,0 145 | 469003,儋州市,0 146 | 469005,文昌市,0 147 | 469033,乐东黎族自治县,0 148 | 4602,三亚市,2 149 | 469036,琼中黎族苗族自治县,0 150 | 469007,东方市,0 151 | 4601,海口市,2 152 | 469006,万宁市,1 153 | 469027,澄迈县,0 154 | 469030,白沙黎族自治县,0 155 | 469002,琼海市,1 156 | 469031,昌江黎族自治县,0 157 | 469028,临高县,0 158 | 469034,陵水黎族自治县,1 159 | 469026,屯昌县,0 160 | 469025,定安县,1 161 | 469035,保亭黎族苗族自治县,0 162 | 469001,五指山市,0 163 | 1308,承德市,0 164 | 1307,张家口市,0 165 | 1306,保定市,0 166 | 1302,唐山市,0 167 | 1309,沧州市,0 168 | 1301,石家庄市,0 169 | 1305,邢台市,0 170 | 1304,邯郸市,0 171 | 1303,秦皇岛市,2 172 | 1311,衡水市,0 173 | 1310,廊坊市,0 174 | 4113,南阳市,0 175 | 4115,信阳市,0 176 | 4103,洛阳市,0 177 | 4117,驻马店市,0 178 | 4116,周口市,0 179 | 4114,商丘市,0 180 | 4112,三门峡市,0 181 | 4107,新乡市,0 182 | 4104,平顶山市,0 183 | 4101,郑州市,0 184 | 4105,安阳市,0 185 | 4102,开封市,0 186 | 4108,焦作市,0 187 | 4110,许昌市,0 188 | 4109,濮阳市,0 189 | 4111,漯河市,0 190 | 4106,鹤壁市,0 191 | 2311,黑河市,0 192 | 2327,大兴安岭地区,0 193 | 2301,哈尔滨市,0 194 | 2302,齐齐哈尔市,0 195 | 2310,牡丹江市,0 196 | 2312,绥化市,0 197 | 2307,伊春市,0 198 | 2308,佳木斯市,0 199 | 2303,鸡西市,0 200 | 2305,双鸭山市,0 201 | 2306,大庆市,0 202 | 2304,鹤岗市,0 203 | 2309,七台河市,0 204 | 4228,恩施土家族苗族自治州,0 205 | 4203,十堰市,0 206 | 4205,宜昌市,0 207 | 4206,襄樊市,0 208 | 4211,黄冈市,0 209 | 4210,荆州市,0 210 | 4208,荆门市,0 211 | 4212,咸宁市,0 212 | 4213,随州市,0 213 | 4209,孝感市,0 214 | 4201,武汉市,0 215 | 4202,黄石市,0 216 | 429021,神农架林区,0 217 | 429006,天门市,0 218 | 429004,仙桃市,0 219 | 429005,潜江市,0 220 | 4207,鄂州市,0 221 | 4312,怀化市,0 222 | 4311,永州市,0 223 | 4305,邵阳市,0 224 | 4310,郴州市,0 225 | 4307,常德市,0 226 | 4331,湘西土家族苗族自治州,0 227 | 4304,衡阳市,0 228 | 4306,岳阳市,0 229 | 4309,益阳市,0 230 | 4301,长沙市,0 231 | 4302,株洲市,0 232 | 4308,张家界市,0 233 | 4313,娄底市,0 234 | 4303,湘潭市,0 235 | 2224,延边朝鲜族自治州,0 236 | 2202,吉林市,0 237 | 2208,白城市,0 238 | 2207,松原市,0 239 | 2201,长春市,0 240 | 2206,白山市,0 241 | 2205,通化市,0 242 | 2203,四平市,0 243 | 2204,辽源市,0 244 | 3209,盐城市,0 245 | 3203,徐州市,0 246 | 3206,南通市,0 247 | 3208,淮安市,0 248 | 3205,苏州市,1 249 | 3213,宿迁市,0 250 | 3207,连云港市,0 251 | 3210,扬州市,0 252 | 3201,南京市,1 253 | 3212,泰州市,0 254 | 3202,无锡市,2 255 | 3204,常州市,0 256 | 3211,镇江市,0 257 | 3607,赣州市,0 258 | 3608,吉安市,0 259 | 3611,上饶市,0 260 | 3604,九江市,0 261 | 3610,抚州市,0 262 | 3609,宜春市,0 263 | 3601,南昌市,0 264 | 3602,景德镇市,0 265 | 3603,萍乡市,0 266 | 3606,鹰潭市,0 267 | 3605,新余市,0 268 | 2102,大连市,0 269 | 2113,朝阳市,0 270 | 2106,丹东市,0 271 | 2112,铁岭市,0 272 | 2101,沈阳市,0 273 | 2104,抚顺市,0 274 | 2114,葫芦岛市,0 275 | 2109,阜新市,0 276 | 2107,锦州市,0 277 | 2103,鞍山市,0 278 | 2105,本溪市,0 279 | 2108,营口市,0 280 | 2110,辽阳市,0 281 | 2111,盘锦市,0 282 | 1507,呼伦贝尔市,0 283 | 1529,阿拉善盟,0 284 | 1525,锡林郭勒盟,0 285 | 1506,鄂尔多斯市,0 286 | 1504,赤峰市,0 287 | 1508,巴彦淖尔市,0 288 | 1505,通辽市,0 289 | 1509,乌兰察布市,0 290 | 1522,兴安盟,0 291 | 1502,包头市,0 292 | 1501,呼和浩特市,0 293 | 1503,乌海市,0 294 | 6403,吴忠市,0 295 | 6405,中卫市,0 296 | 6404,固原市,0 297 | 6401,银川市,0 298 | 6402,石嘴山市,0 299 | 6328,海西蒙古族藏族自治州,0 300 | 6327,玉树藏族自治州,0 301 | 6326,果洛藏族自治州,0 302 | 6325,海南藏族自治州,0 303 | 6322,海北藏族自治州,0 304 | 6323,黄南藏族自治州,0 305 | 6321,海东地区,0 306 | 6301,西宁市,0 307 | 3706,烟台市,0 308 | 3713,临沂市,0 309 | 3707,潍坊市,0 310 | 3702,青岛市,0 311 | 3717,菏泽市,0 312 | 3708,济宁市,1 313 | 3714,德州市,0 314 | 3716,滨州市,0 315 | 3715,聊城市,0 316 | 3705,东营市,0 317 | 3701,济南市,2 318 | 3709,泰安市,2 319 | 3710,威海市,0 320 | 3711,日照市,0 321 | 3703,淄博市,0 322 | 3704,枣庄市,0 323 | 3712,莱芜市,0 324 | 6108,榆林市,0 325 | 6106,延安市,0 326 | 6107,汉中市,0 327 | 6109,安康市,0 328 | 6110,商洛市,0 329 | 6103,宝鸡市,0 330 | 6105,渭南市,0 331 | 6104,咸阳市,0 332 | 6101,西安市,2 333 | 6102,铜川市,0 334 | 1409,忻州市,0 335 | 1411,吕梁市,0 336 | 1410,临汾市,0 337 | 1407,晋中市,2 338 | 1408,运城市,0 339 | 1402,大同市,0 340 | 1404,长治市,0 341 | 1406,朔州市,0 342 | 1405,晋城市,0 343 | 1401,太原市,2 344 | 1403,阳泉市,0 345 | 310230,崇明县,0 346 | 310119,南汇区,1 347 | 310120,奉贤区,0 348 | 310115,浦东新区,2 349 | 310116,金山区,0 350 | 310118,青浦区,1 351 | 310117,松江区,0 352 | 310114,嘉定区,0 353 | 310113,宝山区,0 354 | 310112,闵行区,1 355 | 310110,杨浦区,3 356 | 310107,普陀区,1 357 | 310104,徐汇区,2 358 | 310105,长宁区,0 359 | 310108,闸北区,1 360 | 310109,虹口区,1 361 | 310101,黄浦区,2 362 | 310103,卢湾区,2 363 | 310106,静安区,2 364 | 5133,甘孜藏族自治州,0 365 | 5132,阿坝藏族羌族自治州,0 366 | 5134,凉山彝族自治州,0 367 | 5107,绵阳市,0 368 | 5117,达州市,0 369 | 5108,广元市,0 370 | 5118,雅安市,0 371 | 5115,宜宾市,0 372 | 5111,乐山市,0 373 | 5113,南充市,0 374 | 5119,巴中市,0 375 | 5105,泸州市,0 376 | 5101,成都市,0 377 | 5120,资阳市,0 378 | 5104,攀枝花市,0 379 | 5114,眉山市,0 380 | 5116,广安市,0 381 | 5106,德阳市,0 382 | 5110,内江市,0 383 | 5109,遂宁市,0 384 | 5103,自贡市,0 385 | 7100,台湾,0 386 | 120225,蓟县,0 387 | 120114,武清区,0 388 | 120115,宝坻区,0 389 | 120223,静海县,0 390 | 120221,宁河县,0 391 | 120109,大港区,0 392 | 120107,塘沽区,0 393 | 120111,西青区,0 394 | 120113,北辰区,0 395 | 120110,东丽区,0 396 | 120108,汉沽区,0 397 | 120112,津南区,0 398 | 120103,河西区,0 399 | 120102,河东区,0 400 | 120104,南开区,0 401 | 120105,河北区,0 402 | 120106,红桥区,0 403 | 120101,和平区,0 404 | 5424,那曲地区,0 405 | 5425,阿里地区,0 406 | 5423,日喀则地区,0 407 | 5426,林芝地区,0 408 | 5421,昌都地区,0 409 | 5422,山南地区,0 410 | 5401,拉萨市,0 411 | 8100,香港,0 412 | 6528,巴音郭楞蒙古自治州,0 413 | 6532,和田地区,0 414 | 6522,哈密地区,0 415 | 6529,阿克苏地区,0 416 | 6543,阿勒泰地区,0 417 | 6531,喀什地区,0 418 | 6542,塔城地区,0 419 | 6523,昌吉回族自治州,0 420 | 6530,克孜勒苏柯尔克孜自治州,0 421 | 6521,吐鲁番地区,0 422 | 6540,伊犁哈萨克自治州,0 423 | 6527,博尔塔拉蒙古自治州,0 424 | 6501,乌鲁木齐市,0 425 | 6502,克拉玛依市,0 426 | 659002,阿拉尔市,0 427 | 659003,图木舒克市,0 428 | 659004,五家渠市,0 429 | 659001,石河子市,0 430 | 5308,普洱市,0 431 | 5325,红河哈尼族彝族自治州,0 432 | 5326,文山壮族苗族自治州,0 433 | 5303,曲靖市,0 434 | 5323,楚雄彝族自治州,1 435 | 5329,大理白族自治州,2 436 | 5309,临沧市,0 437 | 5334,迪庆藏族自治州,2 438 | 5306,昭通市,0 439 | 5301,昆明市,2 440 | 5307,丽江市,2 441 | 5328,西双版纳傣族自治州,0 442 | 5305,保山市,0 443 | 5304,玉溪市,0 444 | 5333,怒江傈僳族自治州,0 445 | 5331,德宏傣族景颇族自治州,0 446 | 3311,丽水市,2 447 | 3301,杭州市,4 448 | 3303,温州市,1 449 | 3302,宁波市,2 450 | 3309,舟山市,0 451 | 3310,台州市,0 452 | 3307,金华市,4 453 | 3308,衢州市,2 454 | 3306,绍兴市,1 455 | 3304,嘉兴市,1 456 | 3305,湖州市,0 457 | -------------------------------------------------------------------------------- /data/china_provinces.json: -------------------------------------------------------------------------------- 1 | {"type":"FeatureCollection","features":[{"type":"Feature","id":"xin_jiang","properties":{"name":"新疆","cp":[84.9023,41.748],"childNum":18},"geometry":{"type":"Polygon","coordinates":[[[96.416,42.7588],[96.416,42.7148],[95.9766,42.4951],[96.0645,42.3193],[96.2402,42.2314],[95.9766,41.9238],[95.2734,41.6162],[95.1855,41.792],[94.5703,41.4844],[94.043,41.0889],[93.8672,40.6934],[93.0762,40.6494],[92.6367,39.6387],[92.373,39.3311],[92.373,39.1113],[92.373,39.0234],[90.1758,38.4961],[90.3516,38.2324],[90.6152,38.3203],[90.5273,37.8369],[91.0547,37.4414],[91.3184,37.0898],[90.7031,36.7822],[90.791,36.6064],[91.0547,36.5186],[91.0547,36.0791],[90.8789,36.0352],[90,36.2549],[89.9121,36.0791],[89.7363,36.0791],[89.209,36.2988],[88.7695,36.3428],[88.5938,36.4746],[87.3633,36.4307],[86.2207,36.167],[86.1328,35.8594],[85.6055,35.6836],[85.0781,35.7275],[84.1992,35.376],[83.1445,35.4199],[82.8809,35.6836],[82.4414,35.7275],[82.002,35.332],[81.6504,35.2441],[80.4199,35.4199],[80.2441,35.2881],[80.332,35.1563],[80.2441,35.2002],[79.8926,34.8047],[79.8047,34.4971],[79.1016,34.4531],[79.0137,34.3213],[78.2227,34.7168],[78.0469,35.2441],[78.0469,35.5078],[77.4316,35.4639],[76.8164,35.6396],[76.5527,35.8594],[76.2012,35.8154],[75.9375,36.0352],[76.0254,36.4746],[75.8496,36.6943],[75.498,36.7383],[75.4102,36.958],[75.0586,37.002],[74.8828,36.9141],[74.7949,37.0459],[74.5313,37.0898],[74.5313,37.2217],[74.8828,37.2217],[75.1465,37.4414],[74.8828,37.5732],[74.9707,37.749],[74.8828,38.4521],[74.3555,38.6719],[74.1797,38.6719],[74.0918,38.54],[73.8281,38.584],[73.7402,38.8477],[73.8281,38.9795],[73.4766,39.375],[73.916,39.5068],[73.916,39.6826],[73.8281,39.7705],[74.0039,40.0342],[74.8828,40.3418],[74.7949,40.5176],[75.2344,40.4297],[75.5859,40.6494],[75.7617,40.2979],[76.377,40.3857],[76.9043,41.001],[77.6074,41.001],[78.1348,41.2207],[78.1348,41.3965],[80.1563,42.0557],[80.2441,42.2754],[80.1563,42.627],[80.2441,42.8467],[80.5078,42.8906],[80.4199,43.0664],[80.7715,43.1982],[80.4199,44.165],[80.4199,44.6045],[79.9805,44.8242],[79.9805,44.9561],[81.7383,45.3955],[82.0898,45.2197],[82.5293,45.2197],[82.2656,45.6592],[83.0566,47.2412],[83.6719,47.0215],[84.7266,47.0215],[84.9023,46.8896],[85.5176,47.0654],[85.6934,47.2852],[85.5176,48.1201],[85.7813,48.4277],[86.5723,48.5596],[86.8359,48.8232],[86.748,48.9551],[86.8359,49.1309],[87.8027,49.1748],[87.8906,48.999],[87.7148,48.9111],[88.0664,48.7354],[87.9785,48.6035],[88.5059,48.3838],[88.6816,48.1641],[89.1211,47.9883],[89.5605,48.0322],[89.7363,47.8564],[90.0879,47.8564],[90.3516,47.6807],[90.5273,47.2412],[90.8789,46.9775],[91.0547,46.582],[90.8789,46.3184],[91.0547,46.0107],[90.7031,45.7471],[90.7031,45.5273],[90.8789,45.2197],[91.582,45.0879],[93.5156,44.9561],[94.7461,44.3408],[95.3613,44.2969],[95.3613,44.0332],[95.5371,43.9014],[95.8887,43.2422],[96.3281,42.9346],[96.416,42.7588]]]}},{"type":"Feature","id":"xi_zang","properties":{"name":"西藏","cp":[88.7695,31.6846],"childNum":7},"geometry":{"type":"Polygon","coordinates":[[[79.0137,34.3213],[79.1016,34.4531],[79.8047,34.4971],[79.8926,34.8047],[80.2441,35.2002],[80.332,35.1563],[80.2441,35.2881],[80.4199,35.4199],[81.6504,35.2441],[82.002,35.332],[82.4414,35.7275],[82.8809,35.6836],[83.1445,35.4199],[84.1992,35.376],[85.0781,35.7275],[85.6055,35.6836],[86.1328,35.8594],[86.2207,36.167],[87.3633,36.4307],[88.5938,36.4746],[88.7695,36.3428],[89.209,36.2988],[89.7363,36.0791],[89.3848,36.0352],[89.4727,35.9033],[89.7363,35.7715],[89.7363,35.4199],[89.4727,35.376],[89.4727,35.2441],[89.5605,34.8926],[89.8242,34.8486],[89.7363,34.6729],[89.8242,34.3652],[89.6484,34.0137],[90.0879,33.4863],[90.7031,33.1348],[91.4063,33.1348],[91.9336,32.8271],[92.1973,32.8271],[92.2852,32.7393],[92.9883,32.7393],[93.5156,32.4756],[93.7793,32.5635],[94.1309,32.4316],[94.6582,32.6074],[95.1855,32.4316],[95.0098,32.2998],[95.1855,32.3438],[95.2734,32.2119],[95.3613,32.168],[95.3613,31.9922],[95.4492,31.8164],[95.8008,31.6846],[95.9766,31.8164],[96.1523,31.5967],[96.2402,31.9482],[96.5039,31.7285],[96.8555,31.6846],[96.7676,31.9922],[97.2949,32.0801],[97.3828,32.5635],[97.7344,32.5195],[98.1738,32.3438],[98.4375,31.8604],[98.877,31.4209],[98.6133,31.2012],[98.9648,30.7617],[99.1406,29.2676],[98.9648,29.1357],[98.9648,28.8281],[98.7891,28.8721],[98.7891,29.0039],[98.7012,28.916],[98.6133,28.5205],[98.7891,28.3447],[98.7012,28.2129],[98.3496,28.125],[98.2617,28.3887],[98.1738,28.125],[97.5586,28.5205],[97.2949,28.0811],[97.3828,27.9053],[97.0313,27.7295],[96.5039,28.125],[95.7129,28.2568],[95.3613,28.125],[95.2734,27.9492],[94.2188,27.5537],[93.8672,27.0264],[93.6035,26.9385],[92.1094,26.8506],[92.0215,27.4658],[91.582,27.5537],[91.582,27.9053],[91.4063,28.0371],[91.0547,27.8613],[90.7031,28.0811],[89.8242,28.2129],[89.6484,28.1689],[89.1211,27.5977],[89.1211,27.334],[89.0332,27.2021],[88.7695,27.4219],[88.8574,27.9932],[88.6816,28.125],[88.1543,27.9053],[87.8906,27.9492],[87.7148,27.8174],[87.0996,27.8174],[86.748,28.125],[86.5723,28.125],[86.4844,27.9053],[86.1328,28.125],[86.0449,27.9053],[85.6934,28.3447],[85.6055,28.2568],[85.166,28.3447],[85.166,28.6523],[84.9023,28.5645],[84.4629,28.7402],[84.2871,28.8721],[84.1992,29.2236],[84.1113,29.2676],[83.584,29.1797],[83.2324,29.5752],[82.1777,30.0586],[82.0898,30.3223],[81.3867,30.3662],[81.2109,30.0146],[81.0352,30.2344],[80.0684,30.5859],[79.7168,30.9375],[79.0137,31.0693],[78.75,31.333],[78.8379,31.5967],[78.6621,31.8164],[78.75,31.9043],[78.4863,32.124],[78.3984,32.5195],[78.75,32.6953],[78.9258,32.3438],[79.2773,32.5635],[79.1016,33.1787],[78.6621,33.6621],[78.6621,34.1016],[78.9258,34.1455],[79.0137,34.3213]]]}},{"type":"Feature","id":"nei_meng_gu","properties":{"name":"内蒙古","cp":[117.5977,44.3408],"childNum":12},"geometry":{"type":"Polygon","coordinates":[[[97.207,42.8027],[99.4922,42.583],[100.8105,42.6709],[101.7773,42.4951],[102.041,42.2314],[102.7441,42.1436],[103.3594,41.8799],[103.8867,41.792],[104.502,41.8799],[104.502,41.6602],[105.0293,41.5723],[105.7324,41.9238],[107.4023,42.4512],[109.4238,42.4512],[110.3906,42.7588],[111.0059,43.3301],[111.9727,43.6816],[111.9727,43.8135],[111.4453,44.3848],[111.7969,45],[111.9727,45.0879],[113.6426,44.7363],[114.1699,44.9561],[114.5215,45.3955],[115.6641,45.4395],[116.1914,45.7031],[116.2793,45.9668],[116.543,46.2744],[117.334,46.3623],[117.4219,46.582],[117.7734,46.5381],[118.3008,46.7578],[118.7402,46.7139],[118.916,46.7578],[119.0918,46.6699],[119.707,46.626],[119.9707,46.7139],[119.707,47.1973],[118.4766,47.9883],[117.8613,48.0322],[117.334,47.6807],[116.8066,47.9004],[116.1914,47.8564],[115.9277,47.6807],[115.5762,47.9004],[115.4883,48.1641],[115.8398,48.252],[115.8398,48.5596],[116.7188,49.834],[117.7734,49.5264],[118.5645,49.9219],[119.2676,50.0977],[119.3555,50.3174],[119.1797,50.3613],[119.5313,50.7568],[119.5313,50.8887],[119.707,51.0645],[120.1465,51.6797],[120.6738,51.9434],[120.7617,52.1191],[120.7617,52.251],[120.5859,52.3389],[120.6738,52.5146],[120.4102,52.6465],[120.0586,52.6025],[120.0586,52.7344],[120.8496,53.2617],[121.4648,53.3496],[121.8164,53.042],[121.2012,52.5586],[121.6406,52.4268],[121.7285,52.2949],[121.9922,52.2949],[122.168,52.5146],[122.6953,52.251],[122.6074,52.0752],[122.959,51.3281],[123.3105,51.2402],[123.6621,51.3721],[124.3652,51.2842],[124.541,51.3721],[124.8926,51.3721],[125.0684,51.6357],[125.332,51.6357],[126.0352,51.0205],[125.7715,50.7568],[125.7715,50.5371],[125.332,50.1416],[125.1563,49.834],[125.2441,49.1748],[124.8047,49.1309],[124.4531,48.1201],[124.2773,48.5156],[122.4316,47.373],[123.0469,46.7139],[123.3984,46.8896],[123.3984,46.9775],[123.4863,46.9775],[123.5742,46.8457],[123.5742,46.8896],[123.5742,46.6699],[123.0469,46.582],[123.2227,46.2305],[122.7832,46.0107],[122.6953,45.7031],[122.4316,45.8789],[122.2559,45.791],[121.8164,46.0107],[121.7285,45.7471],[121.9043,45.7031],[122.2559,45.2637],[122.0801,44.8682],[122.3438,44.2529],[123.1348,44.4727],[123.4863,43.7256],[123.3105,43.5059],[123.6621,43.374],[123.5742,43.0225],[123.3105,42.9785],[123.1348,42.8027],[122.7832,42.7148],[122.3438,42.8467],[122.3438,42.6709],[121.9922,42.7148],[121.7285,42.4512],[121.4648,42.4951],[120.498,42.0996],[120.1465,41.7041],[119.8828,42.1875],[119.5313,42.3633],[119.3555,42.2754],[119.2676,41.7041],[119.4434,41.6162],[119.2676,41.3086],[118.3887,41.3086],[118.125,41.748],[118.3008,41.792],[118.3008,42.0996],[118.125,42.0557],[117.9492,42.2314],[118.0371,42.4072],[117.7734,42.627],[117.5098,42.583],[117.334,42.4512],[116.8945,42.4072],[116.8066,42.0117],[116.2793,42.0117],[116.0156,41.792],[115.9277,41.9238],[115.2246,41.5723],[114.9609,41.6162],[114.873,42.0996],[114.5215,42.1436],[114.1699,41.792],[114.2578,41.5723],[113.9063,41.4404],[113.9941,41.2207],[113.9063,41.1328],[114.082,40.7373],[114.082,40.5176],[113.8184,40.5176],[113.5547,40.3418],[113.2031,40.3857],[112.7637,40.166],[112.3242,40.2539],[111.9727,39.5947],[111.4453,39.6387],[111.3574,39.4189],[111.0938,39.375],[111.0938,39.5947],[110.6543,39.2871],[110.127,39.4629],[110.2148,39.2871],[109.8633,39.2432],[109.9512,39.1553],[108.9844,38.3203],[109.0723,38.0127],[108.8965,37.9688],[108.8086,38.0127],[108.7207,37.7051],[108.1934,37.6172],[107.666,37.8809],[107.3145,38.1006],[106.7871,38.1885],[106.5234,38.3203],[106.9629,38.9795],[106.7871,39.375],[106.3477,39.2871],[105.9082,38.7158],[105.8203,37.793],[104.3262,37.4414],[103.4473,37.8369],[103.3594,38.0127],[103.5352,38.1445],[103.4473,38.3643],[104.2383,38.9795],[104.0625,39.4189],[103.3594,39.3311],[103.0078,39.1113],[102.4805,39.2432],[101.8652,39.1113],[102.041,38.8916],[101.7773,38.6719],[101.3379,38.7598],[101.25,39.0234],[100.9863,38.9355],[100.8105,39.4189],[100.5469,39.4189],[100.0195,39.7705],[99.4922,39.8584],[100.1074,40.2539],[100.1953,40.6494],[99.9316,41.001],[99.2285,40.8691],[99.0527,40.6934],[98.9648,40.7813],[98.7891,40.6055],[98.5254,40.7373],[98.6133,40.6494],[98.3496,40.5615],[98.3496,40.9131],[97.4707,41.4844],[97.8223,41.6162],[97.8223,41.748],[97.207,42.8027]]]}},{"type":"Feature","id":"qing_hai","properties":{"name":"青海","cp":[96.2402,35.4199],"childNum":8},"geometry":{"type":"Polygon","coordinates":[[[89.7363,36.0791],[89.9121,36.0791],[90,36.2549],[90.8789,36.0352],[91.0547,36.0791],[91.0547,36.5186],[90.791,36.6064],[90.7031,36.7822],[91.3184,37.0898],[91.0547,37.4414],[90.5273,37.8369],[90.6152,38.3203],[90.3516,38.2324],[90.1758,38.4961],[92.373,39.0234],[92.373,39.1113],[93.1641,39.1992],[93.1641,38.9795],[93.6914,38.9355],[93.8672,38.7158],[94.3066,38.7598],[94.5703,38.3643],[95.0098,38.4082],[95.4492,38.2764],[95.7129,38.3643],[96.2402,38.1006],[96.416,38.2324],[96.6797,38.1885],[96.6797,38.4521],[97.1191,38.584],[97.0313,39.1992],[98.1738,38.8037],[98.3496,39.0234],[98.6133,38.9355],[98.7891,39.0674],[99.1406,38.9355],[99.8438,38.3643],[100.1953,38.2764],[100.0195,38.4521],[100.1074,38.4961],[100.459,38.2764],[100.7227,38.2324],[101.1621,37.8369],[101.5137,37.8809],[101.7773,37.6172],[101.9531,37.7051],[102.1289,37.4414],[102.5684,37.1777],[102.4805,36.958],[102.6563,36.8262],[102.5684,36.7383],[102.832,36.3428],[103.0078,36.2549],[102.9199,36.0791],[102.9199,35.9033],[102.6563,35.7715],[102.832,35.5957],[102.4805,35.5957],[102.3047,35.4199],[102.3926,35.2002],[101.9531,34.8486],[101.9531,34.6289],[102.2168,34.4092],[102.1289,34.2773],[101.6895,34.1016],[100.9863,34.3652],[100.8105,34.2773],[101.25,33.6621],[101.5137,33.7061],[101.6016,33.5303],[101.7773,33.5303],[101.6895,33.3105],[101.7773,33.2227],[101.6016,33.1348],[101.1621,33.2227],[101.25,32.6953],[100.7227,32.6514],[100.7227,32.5195],[100.3711,32.7393],[100.1074,32.6514],[100.1074,32.8711],[99.8438,33.0029],[99.7559,32.7393],[99.2285,32.915],[99.2285,33.0469],[98.877,33.1787],[98.4375,34.0576],[97.8223,34.1895],[97.6465,34.1016],[97.7344,33.9258],[97.3828,33.8818],[97.4707,33.5742],[97.7344,33.3984],[97.3828,32.8711],[97.4707,32.6953],[97.7344,32.5195],[97.3828,32.5635],[97.2949,32.0801],[96.7676,31.9922],[96.8555,31.6846],[96.5039,31.7285],[96.2402,31.9482],[96.1523,31.5967],[95.9766,31.8164],[95.8008,31.6846],[95.4492,31.8164],[95.3613,31.9922],[95.3613,32.168],[95.2734,32.2119],[95.1855,32.3438],[95.0098,32.2998],[95.1855,32.4316],[94.6582,32.6074],[94.1309,32.4316],[93.7793,32.5635],[93.5156,32.4756],[92.9883,32.7393],[92.2852,32.7393],[92.1973,32.8271],[91.9336,32.8271],[91.4063,33.1348],[90.7031,33.1348],[90.0879,33.4863],[89.6484,34.0137],[89.8242,34.3652],[89.7363,34.6729],[89.8242,34.8486],[89.5605,34.8926],[89.4727,35.2441],[89.4727,35.376],[89.7363,35.4199],[89.7363,35.7715],[89.4727,35.9033],[89.3848,36.0352],[89.7363,36.0791]]]}},{"type":"Feature","id":"si_chuan","properties":{"name":"四川","cp":[102.9199,30.1904],"childNum":21},"geometry":{"type":"Polygon","coordinates":[[[101.7773,33.5303],[101.8652,33.5742],[101.9531,33.4424],[101.8652,33.0908],[102.4805,33.4424],[102.2168,33.9258],[102.9199,34.3213],[103.0957,34.1895],[103.1836,33.7939],[104.1504,33.6182],[104.2383,33.3984],[104.4141,33.3105],[104.3262,33.2227],[104.4141,33.0469],[104.3262,32.8711],[104.4141,32.7393],[105.2051,32.6074],[105.3809,32.7393],[105.3809,32.8711],[105.4688,32.915],[105.5566,32.7393],[106.084,32.8711],[106.084,32.7393],[106.3477,32.6514],[107.0508,32.6953],[107.1387,32.4756],[107.2266,32.4316],[107.4023,32.5195],[108.0176,32.168],[108.2813,32.2559],[108.5449,32.2119],[108.3691,32.168],[108.2813,31.9043],[108.5449,31.6846],[108.1934,31.5088],[107.9297,30.8496],[107.4902,30.8496],[107.4023,30.7617],[107.4902,30.6299],[107.0508,30.0146],[106.7871,30.0146],[106.6113,30.3223],[106.2598,30.1904],[105.8203,30.4541],[105.6445,30.2783],[105.5566,30.1025],[105.7324,29.8828],[105.293,29.5313],[105.4688,29.3115],[105.7324,29.2676],[105.8203,28.96],[106.2598,28.8721],[106.3477,28.5205],[105.9961,28.7402],[105.6445,28.4326],[105.9082,28.125],[106.1719,28.125],[106.3477,27.8174],[105.6445,27.6416],[105.5566,27.7734],[105.293,27.7295],[105.2051,27.9932],[105.0293,28.0811],[104.8535,27.9053],[104.4141,27.9492],[104.3262,28.0371],[104.4141,28.125],[104.4141,28.2568],[104.2383,28.4326],[104.4141,28.6084],[103.8867,28.6523],[103.7988,28.3008],[103.4473,28.125],[103.4473,27.7734],[102.9199,27.29],[103.0078,26.3672],[102.6563,26.1914],[102.5684,26.3672],[102.1289,26.1035],[101.8652,26.0596],[101.6016,26.2354],[101.6895,26.3672],[101.4258,26.5869],[101.4258,26.8066],[101.4258,26.7188],[101.1621,27.0264],[101.1621,27.1582],[100.7227,27.8613],[100.3711,27.8174],[100.2832,27.7295],[100.0195,28.125],[100.1953,28.3447],[99.668,28.8281],[99.4043,28.5205],[99.4043,28.1689],[99.2285,28.3008],[99.1406,29.2676],[98.9648,30.7617],[98.6133,31.2012],[98.877,31.4209],[98.4375,31.8604],[98.1738,32.3438],[97.7344,32.5195],[97.4707,32.6953],[97.3828,32.8711],[97.7344,33.3984],[97.4707,33.5742],[97.3828,33.8818],[97.7344,33.9258],[97.6465,34.1016],[97.8223,34.1895],[98.4375,34.0576],[98.877,33.1787],[99.2285,33.0469],[99.2285,32.915],[99.7559,32.7393],[99.8438,33.0029],[100.1074,32.8711],[100.1074,32.6514],[100.3711,32.7393],[100.7227,32.5195],[100.7227,32.6514],[101.25,32.6953],[101.1621,33.2227],[101.6016,33.1348],[101.7773,33.2227],[101.6895,33.3105],[101.7773,33.5303]]]}},{"type":"Feature","id":"hei_long_jiang","properties":{"name":"黑龙江","cp":[128.1445,48.5156],"childNum":13},"geometry":{"type":"Polygon","coordinates":[[[121.4648,53.3496],[123.6621,53.5693],[124.8926,53.0859],[125.0684,53.2178],[125.5957,53.0859],[125.6836,52.9102],[126.123,52.7783],[126.0352,52.6025],[126.2109,52.5146],[126.3867,52.2949],[126.3867,52.207],[126.5625,52.1631],[126.4746,51.9434],[126.9141,51.3721],[126.8262,51.2842],[127.002,51.3281],[126.9141,51.1084],[127.2656,50.7568],[127.3535,50.2734],[127.6172,50.2295],[127.5293,49.8779],[127.793,49.6143],[128.7598,49.5703],[129.1113,49.3506],[129.4629,49.4385],[130.2539,48.8672],[130.6934,48.8672],[130.5176,48.6475],[130.8691,48.2959],[130.6934,48.1201],[131.0449,47.6807],[132.5391,47.7246],[132.627,47.9443],[133.0664,48.1201],[133.5059,48.1201],[134.209,48.3838],[135.0879,48.4277],[134.7363,48.252],[134.5605,47.9883],[134.7363,47.6807],[134.5605,47.4609],[134.3848,47.4609],[134.209,47.2852],[134.209,47.1533],[133.8574,46.5381],[133.9453,46.2744],[133.5059,45.835],[133.418,45.5713],[133.2422,45.5273],[133.0664,45.1318],[132.8906,45.0439],[131.9238,45.3516],[131.5723,45.0439],[131.0449,44.8682],[131.3086,44.0771],[131.2207,43.7256],[131.3086,43.4619],[130.8691,43.418],[130.5176,43.6377],[130.3418,43.9893],[129.9902,43.8574],[129.9023,44.0332],[129.8145,43.9014],[129.2871,43.8135],[129.1992,43.5938],[128.8477,43.5498],[128.4961,44.165],[128.4082,44.4727],[128.0566,44.3408],[128.0566,44.1211],[127.7051,44.1211],[127.5293,44.6045],[127.0898,44.6045],[127.002,44.7803],[127.0898,45],[126.9141,45.1318],[126.5625,45.2637],[126.0352,45.1758],[125.7715,45.3076],[125.6836,45.5273],[125.0684,45.3955],[124.8926,45.5273],[124.3652,45.4395],[124.0137,45.7471],[123.9258,46.2305],[123.2227,46.2305],[123.0469,46.582],[123.5742,46.6699],[123.5742,46.8896],[123.5742,46.8457],[123.4863,46.9775],[123.3984,46.9775],[123.3984,46.8896],[123.0469,46.7139],[122.4316,47.373],[124.2773,48.5156],[124.4531,48.1201],[124.8047,49.1309],[125.2441,49.1748],[125.1563,49.834],[125.332,50.1416],[125.7715,50.5371],[125.7715,50.7568],[126.0352,51.0205],[125.332,51.6357],[125.0684,51.6357],[124.8926,51.3721],[124.541,51.3721],[124.3652,51.2842],[123.6621,51.3721],[123.3105,51.2402],[122.959,51.3281],[122.6074,52.0752],[122.6953,52.251],[122.168,52.5146],[121.9922,52.2949],[121.7285,52.2949],[121.6406,52.4268],[121.2012,52.5586],[121.8164,53.042],[121.4648,53.3496]]]}},{"type":"Feature","id":"gan_su","properties":{"name":"甘肃","cp":[95.7129,40.166],"childNum":14},"geometry":{"type":"Polygon","coordinates":[[[96.416,42.7148],[97.207,42.8027],[97.8223,41.748],[97.8223,41.6162],[97.4707,41.4844],[98.3496,40.9131],[98.3496,40.5615],[98.6133,40.6494],[98.5254,40.7373],[98.7891,40.6055],[98.9648,40.7813],[99.0527,40.6934],[99.2285,40.8691],[99.9316,41.001],[100.1953,40.6494],[100.1074,40.2539],[99.4922,39.8584],[100.0195,39.7705],[100.5469,39.4189],[100.8105,39.4189],[100.9863,38.9355],[101.25,39.0234],[101.3379,38.7598],[101.7773,38.6719],[102.041,38.8916],[101.8652,39.1113],[102.4805,39.2432],[103.0078,39.1113],[103.3594,39.3311],[104.0625,39.4189],[104.2383,38.9795],[103.4473,38.3643],[103.5352,38.1445],[103.3594,38.0127],[103.4473,37.8369],[104.3262,37.4414],[104.5898,37.4414],[104.5898,37.2217],[104.8535,37.2217],[105.293,36.8262],[105.2051,36.6943],[105.4688,36.123],[105.293,35.9912],[105.3809,35.7715],[105.7324,35.7275],[105.8203,35.5518],[105.9961,35.4639],[105.9082,35.4199],[105.9961,35.4199],[106.084,35.376],[106.2598,35.4199],[106.3477,35.2441],[106.5234,35.332],[106.4355,35.6836],[106.6992,35.6836],[106.9629,35.8154],[106.875,36.123],[106.5234,36.2549],[106.5234,36.4746],[106.4355,36.5625],[106.6113,36.7822],[106.6113,37.0898],[107.3145,37.0898],[107.3145,36.9141],[108.7207,36.3428],[108.6328,35.9912],[108.5449,35.8594],[108.6328,35.5518],[108.5449,35.2881],[107.7539,35.2881],[107.7539,35.1123],[107.8418,35.0244],[107.666,34.9365],[107.2266,34.8926],[106.9629,35.0684],[106.6113,35.0684],[106.5234,34.7607],[106.3477,34.585],[106.6992,34.3213],[106.5234,34.2773],[106.6113,34.1455],[106.4355,33.9258],[106.5234,33.5303],[105.9961,33.6182],[105.7324,33.3984],[105.9961,33.1787],[105.9082,33.0029],[105.4688,32.915],[105.3809,32.8711],[105.3809,32.7393],[105.2051,32.6074],[104.4141,32.7393],[104.3262,32.8711],[104.4141,33.0469],[104.3262,33.2227],[104.4141,33.3105],[104.2383,33.3984],[104.1504,33.6182],[103.1836,33.7939],[103.0957,34.1895],[102.9199,34.3213],[102.2168,33.9258],[102.4805,33.4424],[101.8652,33.0908],[101.9531,33.4424],[101.8652,33.5742],[101.7773,33.5303],[101.6016,33.5303],[101.5137,33.7061],[101.25,33.6621],[100.8105,34.2773],[100.9863,34.3652],[101.6895,34.1016],[102.1289,34.2773],[102.2168,34.4092],[101.9531,34.6289],[101.9531,34.8486],[102.3926,35.2002],[102.3047,35.4199],[102.4805,35.5957],[102.832,35.5957],[102.6563,35.7715],[102.9199,35.9033],[102.9199,36.0791],[103.0078,36.2549],[102.832,36.3428],[102.5684,36.7383],[102.6563,36.8262],[102.4805,36.958],[102.5684,37.1777],[102.1289,37.4414],[101.9531,37.7051],[101.7773,37.6172],[101.5137,37.8809],[101.1621,37.8369],[100.7227,38.2324],[100.459,38.2764],[100.1074,38.4961],[100.0195,38.4521],[100.1953,38.2764],[99.8438,38.3643],[99.1406,38.9355],[98.7891,39.0674],[98.6133,38.9355],[98.3496,39.0234],[98.1738,38.8037],[97.0313,39.1992],[97.1191,38.584],[96.6797,38.4521],[96.6797,38.1885],[96.416,38.2324],[96.2402,38.1006],[95.7129,38.3643],[95.4492,38.2764],[95.0098,38.4082],[94.5703,38.3643],[94.3066,38.7598],[93.8672,38.7158],[93.6914,38.9355],[93.1641,38.9795],[93.1641,39.1992],[92.373,39.1113],[92.373,39.3311],[92.6367,39.6387],[93.0762,40.6494],[93.8672,40.6934],[94.043,41.0889],[94.5703,41.4844],[95.1855,41.792],[95.2734,41.6162],[95.9766,41.9238],[96.2402,42.2314],[96.0645,42.3193],[95.9766,42.4951],[96.416,42.7148]]]}},{"type":"Feature","id":"yun_nan","properties":{"name":"云南","cp":[101.8652,25.1807],"childNum":16},"geometry":{"type":"Polygon","coordinates":[[[98.1738,28.125],[98.2617,28.3887],[98.3496,28.125],[98.7012,28.2129],[98.7891,28.3447],[98.6133,28.5205],[98.7012,28.916],[98.7891,29.0039],[98.7891,28.8721],[98.9648,28.8281],[98.9648,29.1357],[99.1406,29.2676],[99.2285,28.3008],[99.4043,28.1689],[99.4043,28.5205],[99.668,28.8281],[100.1953,28.3447],[100.0195,28.125],[100.2832,27.7295],[100.3711,27.8174],[100.7227,27.8613],[101.1621,27.1582],[101.1621,27.0264],[101.4258,26.7188],[101.4258,26.8066],[101.4258,26.5869],[101.6895,26.3672],[101.6016,26.2354],[101.8652,26.0596],[102.1289,26.1035],[102.5684,26.3672],[102.6563,26.1914],[103.0078,26.3672],[102.9199,27.29],[103.4473,27.7734],[103.4473,28.125],[103.7988,28.3008],[103.8867,28.6523],[104.4141,28.6084],[104.2383,28.4326],[104.4141,28.2568],[104.4141,28.125],[104.3262,28.0371],[104.4141,27.9492],[104.8535,27.9053],[105.0293,28.0811],[105.2051,27.9932],[105.293,27.7295],[105.2051,27.3779],[104.5898,27.334],[104.4141,27.4658],[104.1504,27.2461],[103.8867,27.4219],[103.623,27.0264],[103.7109,26.9824],[103.7109,26.7627],[103.8867,26.543],[104.4141,26.6748],[104.6777,26.4111],[104.3262,25.708],[104.8535,25.2246],[104.5898,25.0488],[104.6777,24.9609],[104.502,24.7412],[104.6777,24.3457],[104.7656,24.4775],[105.0293,24.4336],[105.2051,24.082],[105.4688,24.0381],[105.5566,24.126],[105.9961,24.126],[106.1719,23.8184],[106.1719,23.5547],[105.6445,23.4229],[105.5566,23.2031],[105.293,23.3789],[104.8535,23.1592],[104.7656,22.8516],[104.3262,22.6758],[104.1504,22.8076],[103.9746,22.5439],[103.623,22.7637],[103.5352,22.5879],[103.3594,22.8076],[103.0957,22.4561],[102.4805,22.7637],[102.3047,22.4121],[101.8652,22.3682],[101.7773,22.5],[101.6016,22.1924],[101.8652,21.6211],[101.7773,21.1377],[101.6016,21.2256],[101.25,21.1816],[101.1621,21.7529],[100.6348,21.4453],[100.1074,21.4893],[99.9316,22.0605],[99.2285,22.1484],[99.4043,22.5879],[99.3164,22.7197],[99.4922,23.0713],[98.877,23.2031],[98.7012,23.9502],[98.877,24.126],[98.1738,24.082],[97.7344,23.8623],[97.5586,23.9063],[97.7344,24.126],[97.6465,24.4336],[97.5586,24.4336],[97.5586,24.7412],[97.7344,24.8291],[97.8223,25.2686],[98.1738,25.4004],[98.1738,25.6201],[98.3496,25.5762],[98.5254,25.8398],[98.7012,25.8838],[98.6133,26.0596],[98.7012,26.1475],[98.7891,26.5869],[98.7012,27.5098],[98.5254,27.6416],[98.3496,27.5098],[98.1738,28.125]]]}},{"type":"Feature","id":"guang_xi","properties":{"name":"广西","cp":[108.2813,23.6426],"childNum":14},"geometry":{"type":"Polygon","coordinates":[[[104.502,24.7412],[104.6777,24.6094],[105.2051,24.9609],[105.9961,24.6533],[106.1719,24.7852],[106.1719,24.9609],[106.875,25.1807],[107.0508,25.2686],[106.9629,25.4883],[107.2266,25.6201],[107.4902,25.2246],[107.7539,25.2246],[107.8418,25.1367],[108.1055,25.2246],[108.1934,25.4443],[108.3691,25.5322],[108.6328,25.3125],[108.6328,25.5762],[109.0723,25.5322],[108.9844,25.752],[109.3359,25.708],[109.5117,26.0156],[109.7754,25.8838],[109.9512,26.1914],[110.2148,25.9717],[110.5664,26.3232],[111.1816,26.3232],[111.2695,26.2354],[111.2695,25.8838],[111.4453,25.8398],[111.0059,25.0049],[111.0938,24.9609],[111.3574,25.1367],[111.5332,24.6533],[111.709,24.7852],[112.0605,24.7412],[111.8848,24.6533],[112.0605,24.3457],[111.8848,24.2139],[111.8848,23.9941],[111.7969,23.8184],[111.6211,23.8184],[111.6211,23.6865],[111.3574,23.4668],[111.4453,23.0273],[111.2695,22.8076],[110.7422,22.5439],[110.7422,22.2803],[110.6543,22.1484],[110.3027,22.1484],[110.3027,21.8848],[109.9512,21.8408],[109.8633,21.665],[109.7754,21.6211],[109.7754,21.4014],[109.5996,21.4453],[109.1602,21.3574],[109.248,20.874],[109.0723,20.9619],[109.0723,21.5332],[108.7207,21.5332],[108.6328,21.665],[108.2813,21.4893],[107.8418,21.6211],[107.4023,21.6211],[107.0508,21.7969],[107.0508,21.9287],[106.6992,22.0166],[106.6113,22.4121],[106.7871,22.7637],[106.6992,22.8955],[105.9082,22.9395],[105.5566,23.0713],[105.5566,23.2031],[105.6445,23.4229],[106.1719,23.5547],[106.1719,23.8184],[105.9961,24.126],[105.5566,24.126],[105.4688,24.0381],[105.2051,24.082],[105.0293,24.4336],[104.7656,24.4775],[104.6777,24.3457],[104.502,24.7412]]]}},{"type":"Feature","id":"hu_nan","properties":{"name":"湖南","cp":[111.5332,27.3779],"childNum":14},"geometry":{"type":"Polygon","coordinates":[[[109.248,28.4766],[109.248,29.1357],[109.5117,29.6191],[109.6875,29.6191],[109.7754,29.751],[110.4785,29.6631],[110.6543,29.751],[110.4785,30.0146],[110.8301,30.1465],[111.7969,29.9268],[112.2363,29.5313],[112.5,29.6191],[112.6758,29.5752],[112.9395,29.7949],[113.0273,29.751],[112.9395,29.4873],[113.0273,29.4434],[113.5547,29.8389],[113.5547,29.707],[113.7305,29.5752],[113.6426,29.3115],[113.7305,29.0918],[113.9063,29.0479],[114.1699,28.8281],[114.082,28.5645],[114.2578,28.3447],[113.7305,27.9492],[113.6426,27.5977],[113.6426,27.3779],[113.8184,27.29],[113.7305,27.1143],[113.9063,26.9385],[113.9063,26.6309],[114.082,26.5869],[113.9941,26.1914],[114.2578,26.1475],[113.9941,26.0596],[113.9063,25.4443],[113.6426,25.3125],[113.2031,25.5322],[112.8516,25.3564],[113.0273,25.2246],[113.0273,24.9609],[112.8516,24.917],[112.5879,25.1367],[112.2363,25.1807],[112.1484,24.873],[112.0605,24.7412],[111.709,24.7852],[111.5332,24.6533],[111.3574,25.1367],[111.0938,24.9609],[111.0059,25.0049],[111.4453,25.8398],[111.2695,25.8838],[111.2695,26.2354],[111.1816,26.3232],[110.5664,26.3232],[110.2148,25.9717],[109.9512,26.1914],[109.7754,25.8838],[109.5117,26.0156],[109.4238,26.2793],[109.248,26.3232],[109.4238,26.5869],[109.3359,26.7188],[109.5117,26.8066],[109.5117,27.0264],[109.3359,27.1582],[108.8965,27.0264],[108.8086,27.1143],[109.4238,27.5977],[109.3359,27.9053],[109.3359,28.2568],[109.248,28.4766]]]}},{"type":"Feature","id":"shan_xi_1","properties":{"name":"陕西","cp":[109.5996,35.6396],"childNum":10},"geometry":{"type":"Polygon","coordinates":[[[105.4688,32.915],[105.9082,33.0029],[105.9961,33.1787],[105.7324,33.3984],[105.9961,33.6182],[106.5234,33.5303],[106.4355,33.9258],[106.6113,34.1455],[106.5234,34.2773],[106.6992,34.3213],[106.3477,34.585],[106.5234,34.7607],[106.6113,35.0684],[106.9629,35.0684],[107.2266,34.8926],[107.666,34.9365],[107.8418,35.0244],[107.7539,35.1123],[107.7539,35.2881],[108.5449,35.2881],[108.6328,35.5518],[108.5449,35.8594],[108.6328,35.9912],[108.7207,36.3428],[107.3145,36.9141],[107.3145,37.0898],[107.3145,37.6172],[107.666,37.8809],[108.1934,37.6172],[108.7207,37.7051],[108.8086,38.0127],[108.8965,37.9688],[109.0723,38.0127],[108.9844,38.3203],[109.9512,39.1553],[109.8633,39.2432],[110.2148,39.2871],[110.127,39.4629],[110.6543,39.2871],[111.0938,39.5947],[111.0938,39.375],[111.1816,39.2432],[110.918,38.7158],[110.8301,38.4961],[110.4785,38.1885],[110.4785,37.9688],[110.8301,37.6611],[110.3906,37.002],[110.4785,36.123],[110.5664,35.6396],[110.2148,34.8926],[110.2148,34.6729],[110.3906,34.585],[110.4785,34.2334],[110.6543,34.1455],[110.6543,33.8379],[111.0059,33.5303],[111.0059,33.2666],[110.7422,33.1348],[110.5664,33.2666],[110.3027,33.1787],[109.5996,33.2666],[109.4238,33.1348],[109.7754,33.0469],[109.7754,32.915],[110.127,32.7393],[110.127,32.6074],[109.6875,32.6074],[109.5117,32.4316],[109.5996,31.7285],[109.248,31.7285],[109.0723,31.9482],[108.5449,32.2119],[108.2813,32.2559],[108.0176,32.168],[107.4023,32.5195],[107.2266,32.4316],[107.1387,32.4756],[107.0508,32.6953],[106.3477,32.6514],[106.084,32.7393],[106.084,32.8711],[105.5566,32.7393],[105.4688,32.915]]]}},{"type":"Feature","id":"guang_dong","properties":{"name":"广东","cp":[113.4668,22.8076],"childNum":21},"geometry":{"type":"Polygon","coordinates":[[[109.7754,21.4014],[109.7754,21.6211],[109.8633,21.665],[109.9512,21.8408],[110.3027,21.8848],[110.3027,22.1484],[110.6543,22.1484],[110.7422,22.2803],[110.7422,22.5439],[111.2695,22.8076],[111.4453,23.0273],[111.3574,23.4668],[111.6211,23.6865],[111.6211,23.8184],[111.7969,23.8184],[111.8848,23.9941],[111.8848,24.2139],[112.0605,24.3457],[111.8848,24.6533],[112.0605,24.7412],[112.1484,24.873],[112.2363,25.1807],[112.5879,25.1367],[112.8516,24.917],[113.0273,24.9609],[113.0273,25.2246],[112.8516,25.3564],[113.2031,25.5322],[113.6426,25.3125],[113.9063,25.4443],[113.9941,25.2686],[114.6094,25.4004],[114.7852,25.2686],[114.6973,25.1367],[114.4336,24.9609],[114.1699,24.6973],[114.4336,24.5215],[115.4004,24.7852],[115.8398,24.5654],[115.752,24.7852],[115.9277,24.917],[116.2793,24.7852],[116.3672,24.873],[116.543,24.6094],[116.7188,24.6533],[116.9824,24.1699],[116.9824,23.9063],[117.1582,23.5547],[117.334,23.2471],[116.8945,23.3789],[116.6309,23.1152],[116.543,22.8516],[115.9277,22.7197],[115.6641,22.7637],[115.5762,22.6318],[115.0488,22.6758],[114.6094,22.3682],[114.3457,22.5439],[113.9941,22.5],[113.8184,22.1924],[114.3457,22.1484],[114.4336,22.0166],[114.082,21.9287],[113.9941,21.7969],[113.5547,22.0166],[113.1152,21.8408],[112.9395,21.5771],[112.4121,21.4453],[112.2363,21.5332],[111.5332,21.4893],[111.2695,21.3574],[110.7422,21.3574],[110.6543,21.2256],[110.7422,20.918],[110.4785,20.874],[110.6543,20.2588],[110.5664,20.2588],[110.3906,20.127],[110.0391,20.127],[109.8633,20.127],[109.8633,20.3027],[109.5996,20.918],[109.7754,21.4014],[109.7754,21.4014]],[[113.5986,22.1649],[113.6096,22.1265],[113.5547,22.11],[113.5437,22.2034],[113.5767,22.2034],[113.5986,22.1649]]]}},{"type":"Feature","id":"ji_lin","properties":{"name":"吉林","cp":[126.4746,43.5938],"childNum":9},"geometry":{"type":"Polygon","coordinates":[[[123.2227,46.2305],[123.9258,46.2305],[124.0137,45.7471],[124.3652,45.4395],[124.8926,45.5273],[125.0684,45.3955],[125.6836,45.5273],[125.7715,45.3076],[126.0352,45.1758],[126.5625,45.2637],[126.9141,45.1318],[127.0898,45],[127.002,44.7803],[127.0898,44.6045],[127.5293,44.6045],[127.7051,44.1211],[128.0566,44.1211],[128.0566,44.3408],[128.4082,44.4727],[128.4961,44.165],[128.8477,43.5498],[129.1992,43.5938],[129.2871,43.8135],[129.8145,43.9014],[129.9023,44.0332],[129.9902,43.8574],[130.3418,43.9893],[130.5176,43.6377],[130.8691,43.418],[131.3086,43.4619],[131.3086,43.3301],[131.1328,42.9346],[130.4297,42.7148],[130.6055,42.6709],[130.6055,42.4512],[130.2539,42.7588],[130.2539,42.8906],[130.166,42.9785],[129.9023,43.0225],[129.7266,42.4951],[129.375,42.4512],[128.9355,42.0117],[128.0566,42.0117],[128.3203,41.5723],[128.1445,41.3525],[127.0898,41.5283],[127.1777,41.5723],[126.9141,41.792],[126.6504,41.6602],[126.4746,41.3965],[126.123,40.957],[125.6836,40.8691],[125.5957,40.9131],[125.7715,41.2207],[125.332,41.6602],[125.332,41.9678],[125.4199,42.0996],[125.332,42.1436],[124.8926,42.8027],[124.8926,43.0664],[124.7168,43.0664],[124.4531,42.8467],[124.2773,43.2422],[123.8379,43.4619],[123.6621,43.374],[123.3105,43.5059],[123.4863,43.7256],[123.1348,44.4727],[122.3438,44.2529],[122.0801,44.8682],[122.2559,45.2637],[121.9043,45.7031],[121.7285,45.7471],[121.8164,46.0107],[122.2559,45.791],[122.4316,45.8789],[122.6953,45.7031],[122.7832,46.0107],[123.2227,46.2305]]]}},{"type":"Feature","id":"he_bei","properties":{"name":"河北","cp":[115.4004,37.9688],"childNum":11},"geometry":{"type":"MultiPolygon","coordinates":[[[[114.5215,39.5068],[114.3457,39.8584],[113.9941,39.9902],[114.5215,40.3418],[114.3457,40.3857],[114.2578,40.6055],[114.082,40.7373],[113.9063,41.1328],[113.9941,41.2207],[113.9063,41.4404],[114.2578,41.5723],[114.1699,41.792],[114.5215,42.1436],[114.873,42.0996],[114.9609,41.6162],[115.2246,41.5723],[115.9277,41.9238],[116.0156,41.792],[116.2793,42.0117],[116.8066,42.0117],[116.8945,42.4072],[117.334,42.4512],[117.5098,42.583],[117.7734,42.627],[118.0371,42.4072],[117.9492,42.2314],[118.125,42.0557],[118.3008,42.0996],[118.3008,41.792],[118.125,41.748],[118.3887,41.3086],[119.2676,41.3086],[118.8281,40.8252],[119.2676,40.5176],[119.5313,40.5615],[119.707,40.1221],[119.8828,39.9463],[119.5313,39.6826],[119.4434,39.4189],[118.916,39.0674],[118.4766,38.9355],[118.125,39.0234],[118.0371,39.1992],[118.0371,39.2432],[117.8613,39.4189],[117.9492,39.5947],[117.6855,39.5947],[117.5098,39.7705],[117.5098,39.9902],[117.6855,39.9902],[117.6855,40.0781],[117.4219,40.21],[117.2461,40.5176],[117.4219,40.6494],[116.9824,40.6934],[116.6309,41.0449],[116.3672,40.9131],[116.4551,40.7813],[116.1914,40.7813],[116.1035,40.6055],[115.752,40.5615],[115.9277,40.2539],[115.4004,39.9463],[115.4883,39.6387],[115.752,39.5068],[116.1914,39.5947],[116.3672,39.4629],[116.543,39.5947],[116.8066,39.5947],[116.8945,39.1113],[116.7188,38.9355],[116.7188,38.8037],[117.2461,38.54],[117.5977,38.6279],[117.9492,38.3203],[117.4219,37.8369],[116.8066,37.8369],[116.4551,37.4854],[116.2793,37.5732],[116.2793,37.3535],[116.0156,37.3535],[115.752,36.9141],[115.3125,36.5186],[115.4883,36.167],[115.3125,36.0791],[115.1367,36.2109],[114.9609,36.0791],[114.873,36.123],[113.7305,36.3428],[113.4668,36.6504],[113.7305,36.8701],[113.7305,37.1338],[114.1699,37.6611],[113.9941,37.7051],[113.8184,38.1445],[113.5547,38.2764],[113.5547,38.54],[113.8184,38.8037],[113.8184,38.9355],[113.9063,39.0234],[114.3457,39.0674],[114.5215,39.5068]]],[[[117.2461,40.0781],[117.1582,39.8145],[117.1582,39.6387],[116.8945,39.6826],[116.8945,39.8145],[116.8066,39.9902],[117.2461,40.0781]]]]}},{"type":"Feature","id":"hu_bei","properties":{"name":"湖北","cp":[112.2363,31.1572],"childNum":17},"geometry":{"type":"Polygon","coordinates":[[[110.2148,31.1572],[110.127,31.377],[109.6875,31.5527],[109.7754,31.6846],[109.5996,31.7285],[109.5117,32.4316],[109.6875,32.6074],[110.127,32.6074],[110.127,32.7393],[109.7754,32.915],[109.7754,33.0469],[109.4238,33.1348],[109.5996,33.2666],[110.3027,33.1787],[110.5664,33.2666],[110.7422,33.1348],[111.0059,33.2666],[111.5332,32.6074],[112.3242,32.3438],[113.2031,32.4316],[113.4668,32.2998],[113.7305,32.4316],[113.8184,31.8604],[113.9941,31.7725],[114.1699,31.8604],[114.5215,31.7725],[114.6094,31.5527],[114.7852,31.4648],[115.1367,31.5967],[115.2246,31.4209],[115.4004,31.4209],[115.5762,31.2012],[116.0156,31.0254],[115.752,30.6738],[116.1035,30.1904],[116.1035,29.8389],[115.9277,29.707],[115.4883,29.7949],[114.873,29.3994],[114.2578,29.3555],[113.9063,29.0479],[113.7305,29.0918],[113.6426,29.3115],[113.7305,29.5752],[113.5547,29.707],[113.5547,29.8389],[113.0273,29.4434],[112.9395,29.4873],[113.0273,29.751],[112.9395,29.7949],[112.6758,29.5752],[112.5,29.6191],[112.2363,29.5313],[111.7969,29.9268],[110.8301,30.1465],[110.4785,30.0146],[110.6543,29.751],[110.4785,29.6631],[109.7754,29.751],[109.6875,29.6191],[109.5117,29.6191],[109.248,29.1357],[109.0723,29.3555],[108.9844,29.3115],[108.6328,29.8389],[108.457,29.7949],[108.5449,30.2344],[108.457,30.4102],[108.6328,30.5859],[108.8086,30.498],[109.0723,30.6299],[109.1602,30.542],[109.248,30.6299],[109.4238,30.542],[109.8633,30.8936],[110.0391,30.8057],[110.2148,31.1572]]]}},{"type":"Feature","id":"gui_zhou","properties":{"name":"贵州","cp":[106.6113,26.9385],"childNum":9},"geometry":{"type":"Polygon","coordinates":[[[104.1504,27.2461],[104.4141,27.4658],[104.5898,27.334],[105.2051,27.3779],[105.293,27.7295],[105.5566,27.7734],[105.6445,27.6416],[106.3477,27.8174],[106.1719,28.125],[105.9082,28.125],[105.6445,28.4326],[105.9961,28.7402],[106.3477,28.5205],[106.5234,28.5645],[106.4355,28.7842],[106.5234,28.7842],[106.6113,28.6523],[106.6113,28.5205],[106.6992,28.4766],[106.875,28.7842],[107.4023,28.8721],[107.4023,29.1797],[107.5781,29.2236],[107.8418,29.1357],[107.8418,29.0039],[108.2813,29.0918],[108.3691,28.6523],[108.5449,28.6523],[108.5449,28.3887],[108.7207,28.4766],[108.7207,28.2129],[109.0723,28.2129],[109.248,28.4766],[109.3359,28.2568],[109.3359,27.9053],[109.4238,27.5977],[108.8086,27.1143],[108.8965,27.0264],[109.3359,27.1582],[109.5117,27.0264],[109.5117,26.8066],[109.3359,26.7188],[109.4238,26.5869],[109.248,26.3232],[109.4238,26.2793],[109.5117,26.0156],[109.3359,25.708],[108.9844,25.752],[109.0723,25.5322],[108.6328,25.5762],[108.6328,25.3125],[108.3691,25.5322],[108.1934,25.4443],[108.1055,25.2246],[107.8418,25.1367],[107.7539,25.2246],[107.4902,25.2246],[107.2266,25.6201],[106.9629,25.4883],[107.0508,25.2686],[106.875,25.1807],[106.1719,24.9609],[106.1719,24.7852],[105.9961,24.6533],[105.2051,24.9609],[104.6777,24.6094],[104.502,24.7412],[104.6777,24.9609],[104.5898,25.0488],[104.8535,25.2246],[104.3262,25.708],[104.6777,26.4111],[104.4141,26.6748],[103.8867,26.543],[103.7109,26.7627],[103.7109,26.9824],[103.623,27.0264],[103.8867,27.4219],[104.1504,27.2461]]]}},{"type":"Feature","id":"shan_dong","properties":{"name":"山东","cp":[118.7402,36.4307],"childNum":17},"geometry":{"type":"Polygon","coordinates":[[[115.4883,36.167],[115.3125,36.5186],[115.752,36.9141],[116.0156,37.3535],[116.2793,37.3535],[116.2793,37.5732],[116.4551,37.4854],[116.8066,37.8369],[117.4219,37.8369],[117.9492,38.3203],[118.125,38.1445],[118.916,38.1445],[119.3555,37.6611],[119.0039,37.5293],[119.0039,37.3535],[119.3555,37.1338],[119.707,37.1338],[119.8828,37.3975],[120.498,37.8369],[120.5859,38.1445],[120.9375,38.4521],[121.0254,37.8369],[121.2012,37.6611],[121.9043,37.4854],[122.168,37.6172],[122.2559,37.4854],[122.6074,37.4854],[122.6953,37.3535],[122.6074,36.9141],[122.4316,36.7822],[121.8164,36.8701],[121.7285,36.6943],[121.1133,36.6064],[121.1133,36.4307],[121.377,36.2549],[120.7617,36.167],[120.9375,35.8594],[120.6738,36.0352],[119.707,35.4639],[119.9707,34.9805],[119.3555,35.0244],[119.2676,35.1123],[118.916,35.0244],[118.7402,34.7168],[118.4766,34.6729],[118.3887,34.4092],[118.2129,34.4092],[118.125,34.6289],[117.9492,34.6729],[117.5977,34.4531],[117.334,34.585],[117.2461,34.4531],[116.8066,34.9365],[116.4551,34.8926],[116.3672,34.6289],[116.1914,34.585],[115.5762,34.585],[115.4004,34.8486],[114.7852,35.0684],[115.0488,35.376],[115.2246,35.4199],[115.4883,35.7275],[116.1035,36.0791],[115.3125,35.8154],[115.4883,36.167]]]}},{"type":"Feature","id":"jiang_xi","properties":{"name":"江西","cp":[116.0156,27.29],"childNum":11},"geometry":{"type":"Polygon","coordinates":[[[114.2578,28.3447],[114.082,28.5645],[114.1699,28.8281],[113.9063,29.0479],[114.2578,29.3555],[114.873,29.3994],[115.4883,29.7949],[115.9277,29.707],[116.1035,29.8389],[116.2793,29.7949],[116.7188,30.0586],[116.8945,29.9268],[116.7188,29.751],[116.7188,29.6191],[117.1582,29.707],[117.0703,29.8389],[117.1582,29.9268],[117.5098,29.6191],[118.0371,29.5752],[118.2129,29.3994],[118.0371,29.1797],[118.0371,29.0479],[118.3887,28.7842],[118.4766,28.3447],[118.4766,28.3008],[118.3008,28.0811],[117.7734,27.8174],[117.5098,27.9932],[116.9824,27.6416],[117.1582,27.29],[117.0703,27.1143],[116.543,26.8066],[116.6309,26.4551],[116.3672,26.2354],[116.4551,26.1035],[116.1914,25.8838],[116.0156,25.2686],[115.8398,25.2246],[115.9277,24.917],[115.752,24.7852],[115.8398,24.5654],[115.4004,24.7852],[114.4336,24.5215],[114.1699,24.6973],[114.4336,24.9609],[114.6973,25.1367],[114.7852,25.2686],[114.6094,25.4004],[113.9941,25.2686],[113.9063,25.4443],[113.9941,26.0596],[114.2578,26.1475],[113.9941,26.1914],[114.082,26.5869],[113.9063,26.6309],[113.9063,26.9385],[113.7305,27.1143],[113.8184,27.29],[113.6426,27.3779],[113.6426,27.5977],[113.7305,27.9492],[114.2578,28.3447]]]}},{"type":"Feature","id":"he_nan","properties":{"name":"河南","cp":[113.4668,33.8818],"childNum":17},"geometry":{"type":"Polygon","coordinates":[[[110.3906,34.585],[110.8301,34.6289],[111.1816,34.8047],[111.5332,34.8486],[111.7969,35.0684],[112.0605,35.0684],[112.0605,35.2881],[112.7637,35.2002],[113.1152,35.332],[113.6426,35.6836],[113.7305,36.3428],[114.873,36.123],[114.9609,36.0791],[115.1367,36.2109],[115.3125,36.0791],[115.4883,36.167],[115.3125,35.8154],[116.1035,36.0791],[115.4883,35.7275],[115.2246,35.4199],[115.0488,35.376],[114.7852,35.0684],[115.4004,34.8486],[115.5762,34.585],[116.1914,34.585],[116.1914,34.4092],[116.543,34.2773],[116.6309,33.9258],[116.1914,33.7061],[116.0156,33.9697],[115.6641,34.0576],[115.5762,33.9258],[115.5762,33.6621],[115.4004,33.5303],[115.3125,33.1787],[114.873,33.1348],[114.873,33.0029],[115.1367,32.8711],[115.2246,32.6074],[115.5762,32.4316],[115.8398,32.5195],[115.9277,31.7725],[115.4883,31.6846],[115.4004,31.4209],[115.2246,31.4209],[115.1367,31.5967],[114.7852,31.4648],[114.6094,31.5527],[114.5215,31.7725],[114.1699,31.8604],[113.9941,31.7725],[113.8184,31.8604],[113.7305,32.4316],[113.4668,32.2998],[113.2031,32.4316],[112.3242,32.3438],[111.5332,32.6074],[111.0059,33.2666],[111.0059,33.5303],[110.6543,33.8379],[110.6543,34.1455],[110.4785,34.2334],[110.3906,34.585]]]}},{"type":"Feature","id":"liao_ning","properties":{"name":"辽宁","cp":[122.3438,41.0889],"childNum":14},"geometry":{"type":"Polygon","coordinates":[[[119.2676,41.3086],[119.4434,41.6162],[119.2676,41.7041],[119.3555,42.2754],[119.5313,42.3633],[119.8828,42.1875],[120.1465,41.7041],[120.498,42.0996],[121.4648,42.4951],[121.7285,42.4512],[121.9922,42.7148],[122.3438,42.6709],[122.3438,42.8467],[122.7832,42.7148],[123.1348,42.8027],[123.3105,42.9785],[123.5742,43.0225],[123.6621,43.374],[123.8379,43.4619],[124.2773,43.2422],[124.4531,42.8467],[124.7168,43.0664],[124.8926,43.0664],[124.8926,42.8027],[125.332,42.1436],[125.4199,42.0996],[125.332,41.9678],[125.332,41.6602],[125.7715,41.2207],[125.5957,40.9131],[125.6836,40.8691],[124.541,40.21],[124.1016,39.6826],[123.3984,39.6826],[123.1348,39.4189],[123.1348,39.0234],[122.0801,39.0234],[121.5527,38.7158],[121.1133,38.6719],[120.9375,38.9795],[121.377,39.1992],[121.2012,39.5508],[122.0801,40.3857],[121.9922,40.6934],[121.7285,40.8252],[121.2012,40.8252],[120.5859,40.21],[119.8828,39.9463],[119.707,40.1221],[119.5313,40.5615],[119.2676,40.5176],[118.8281,40.8252],[119.2676,41.3086]]]}},{"type":"Feature","id":"shan_xi_2","properties":{"name":"山西","cp":[112.4121,37.6611],"childNum":11},"geometry":{"type":"Polygon","coordinates":[[[110.918,38.7158],[111.1816,39.2432],[111.0938,39.375],[111.3574,39.4189],[111.4453,39.6387],[111.9727,39.5947],[112.3242,40.2539],[112.7637,40.166],[113.2031,40.3857],[113.5547,40.3418],[113.8184,40.5176],[114.082,40.5176],[114.082,40.7373],[114.2578,40.6055],[114.3457,40.3857],[114.5215,40.3418],[113.9941,39.9902],[114.3457,39.8584],[114.5215,39.5068],[114.3457,39.0674],[113.9063,39.0234],[113.8184,38.9355],[113.8184,38.8037],[113.5547,38.54],[113.5547,38.2764],[113.8184,38.1445],[113.9941,37.7051],[114.1699,37.6611],[113.7305,37.1338],[113.7305,36.8701],[113.4668,36.6504],[113.7305,36.3428],[113.6426,35.6836],[113.1152,35.332],[112.7637,35.2002],[112.0605,35.2881],[112.0605,35.0684],[111.7969,35.0684],[111.5332,34.8486],[111.1816,34.8047],[110.8301,34.6289],[110.3906,34.585],[110.2148,34.6729],[110.2148,34.8926],[110.5664,35.6396],[110.4785,36.123],[110.3906,37.002],[110.8301,37.6611],[110.4785,37.9688],[110.4785,38.1885],[110.8301,38.4961],[110.918,38.7158]]]}},{"type":"Feature","id":"an_hui","properties":{"name":"安徽","cp":[117.2461,32.0361],"childNum":17},"geometry":{"type":"Polygon","coordinates":[[[116.6309,33.9258],[116.543,34.2773],[116.1914,34.4092],[116.1914,34.585],[116.3672,34.6289],[116.8945,34.4092],[117.1582,34.0576],[117.5977,34.0137],[117.7734,33.7061],[118.125,33.75],[117.9492,33.2227],[118.0371,33.1348],[118.2129,33.2227],[118.3008,32.7832],[118.7402,32.7393],[118.916,32.959],[119.1797,32.8271],[119.1797,32.4756],[118.5645,32.5635],[118.6523,32.2119],[118.4766,32.168],[118.3887,31.9482],[118.916,31.5527],[118.7402,31.377],[118.8281,31.2451],[119.3555,31.2891],[119.4434,31.1572],[119.6191,31.1133],[119.6191,31.0693],[119.4434,30.6738],[119.2676,30.6299],[119.3555,30.4102],[118.916,30.3223],[118.916,29.9707],[118.7402,29.707],[118.2129,29.3994],[118.0371,29.5752],[117.5098,29.6191],[117.1582,29.9268],[117.0703,29.8389],[117.1582,29.707],[116.7188,29.6191],[116.7188,29.751],[116.8945,29.9268],[116.7188,30.0586],[116.2793,29.7949],[116.1035,29.8389],[116.1035,30.1904],[115.752,30.6738],[116.0156,31.0254],[115.5762,31.2012],[115.4004,31.4209],[115.4883,31.6846],[115.9277,31.7725],[115.8398,32.5195],[115.5762,32.4316],[115.2246,32.6074],[115.1367,32.8711],[114.873,33.0029],[114.873,33.1348],[115.3125,33.1787],[115.4004,33.5303],[115.5762,33.6621],[115.5762,33.9258],[115.6641,34.0576],[116.0156,33.9697],[116.1914,33.7061],[116.6309,33.9258]]]}},{"type":"Feature","id":"fu_jian","properties":{"name":"福建","cp":[118.3008,25.9277],"childNum":9},"geometry":{"type":"Polygon","coordinates":[[[118.4766,28.3008],[118.8281,28.2568],[118.7402,28.0371],[118.916,27.4658],[119.2676,27.4219],[119.6191,27.6855],[119.7949,27.29],[120.2344,27.4219],[120.4102,27.1582],[120.7617,27.0264],[120.6738,26.8945],[120.2344,26.8506],[120.2344,26.7188],[120.4102,26.6748],[120.498,26.3672],[120.2344,26.2793],[120.4102,26.1475],[120.0586,26.1914],[119.9707,25.9277],[119.7949,25.9277],[119.9707,25.4004],[119.7949,25.2686],[119.5313,25.1367],[119.4434,25.0049],[119.2676,25.0928],[118.916,24.8291],[118.6523,24.5215],[118.4766,24.5215],[118.4766,24.4336],[118.2129,24.3457],[118.2129,24.1699],[117.8613,23.9941],[117.7734,23.7744],[117.5098,23.5986],[117.1582,23.5547],[116.9824,23.9063],[116.9824,24.1699],[116.7188,24.6533],[116.543,24.6094],[116.3672,24.873],[116.2793,24.7852],[115.9277,24.917],[115.8398,25.2246],[116.0156,25.2686],[116.1914,25.8838],[116.4551,26.1035],[116.3672,26.2354],[116.6309,26.4551],[116.543,26.8066],[117.0703,27.1143],[117.1582,27.29],[116.9824,27.6416],[117.5098,27.9932],[117.7734,27.8174],[118.3008,28.0811],[118.4766,28.3008]]]}},{"type":"Feature","id":"zhe_jiang","properties":{"name":"浙江","cp":[120.498,29.0918],"childNum":11},"geometry":{"type":"Polygon","coordinates":[[[118.2129,29.3994],[118.7402,29.707],[118.916,29.9707],[118.916,30.3223],[119.3555,30.4102],[119.2676,30.6299],[119.4434,30.6738],[119.6191,31.0693],[119.6191,31.1133],[119.9707,31.1572],[120.498,30.8057],[120.9375,31.0254],[121.2891,30.6738],[121.9922,30.8057],[122.6953,30.8936],[122.8711,30.7178],[122.959,30.1465],[122.6074,30.1025],[122.6074,29.9268],[122.168,29.5313],[122.3438,28.8721],[121.9922,28.8721],[121.9922,28.4326],[121.7285,28.3447],[121.7285,28.2129],[121.4648,28.2129],[121.5527,28.0371],[121.2891,27.9492],[121.1133,27.4219],[120.6738,27.334],[120.6738,27.1582],[120.9375,27.0264],[120.7617,27.0264],[120.4102,27.1582],[120.2344,27.4219],[119.7949,27.29],[119.6191,27.6855],[119.2676,27.4219],[118.916,27.4658],[118.7402,28.0371],[118.8281,28.2568],[118.4766,28.3008],[118.4766,28.3447],[118.3887,28.7842],[118.0371,29.0479],[118.0371,29.1797],[118.2129,29.3994]]]}},{"type":"Feature","id":"jiang_su","properties":{"name":"江苏","cp":[120.0586,32.915],"childNum":13},"geometry":{"type":"Polygon","coordinates":[[[116.3672,34.6289],[116.4551,34.8926],[116.8066,34.9365],[117.2461,34.4531],[117.334,34.585],[117.5977,34.4531],[117.9492,34.6729],[118.125,34.6289],[118.2129,34.4092],[118.3887,34.4092],[118.4766,34.6729],[118.7402,34.7168],[118.916,35.0244],[119.2676,35.1123],[119.3555,35.0244],[119.3555,34.8486],[119.707,34.585],[120.3223,34.3652],[120.9375,33.0469],[121.0254,32.6514],[121.377,32.4756],[121.4648,32.168],[121.9043,31.9922],[121.9922,31.6846],[121.9922,31.5967],[121.2012,31.8604],[121.1133,31.7285],[121.377,31.5088],[121.2012,31.4648],[120.9375,31.0254],[120.498,30.8057],[119.9707,31.1572],[119.6191,31.1133],[119.4434,31.1572],[119.3555,31.2891],[118.8281,31.2451],[118.7402,31.377],[118.916,31.5527],[118.3887,31.9482],[118.4766,32.168],[118.6523,32.2119],[118.5645,32.5635],[119.1797,32.4756],[119.1797,32.8271],[118.916,32.959],[118.7402,32.7393],[118.3008,32.7832],[118.2129,33.2227],[118.0371,33.1348],[117.9492,33.2227],[118.125,33.75],[117.7734,33.7061],[117.5977,34.0137],[117.1582,34.0576],[116.8945,34.4092],[116.3672,34.6289]]]}},{"type":"Feature","id":"chong_qing","properties":{"name":"重庆","cp":[107.7539,30.1904],"childNum":40},"geometry":{"type":"Polygon","coordinates":[[[108.5449,31.6846],[108.2813,31.9043],[108.3691,32.168],[108.5449,32.2119],[109.0723,31.9482],[109.248,31.7285],[109.5996,31.7285],[109.7754,31.6846],[109.6875,31.5527],[110.127,31.377],[110.2148,31.1572],[110.0391,30.8057],[109.8633,30.8936],[109.4238,30.542],[109.248,30.6299],[109.1602,30.542],[109.0723,30.6299],[108.8086,30.498],[108.6328,30.5859],[108.457,30.4102],[108.5449,30.2344],[108.457,29.7949],[108.6328,29.8389],[108.9844,29.3115],[109.0723,29.3555],[109.248,29.1357],[109.248,28.4766],[109.0723,28.2129],[108.7207,28.2129],[108.7207,28.4766],[108.5449,28.3887],[108.5449,28.6523],[108.3691,28.6523],[108.2813,29.0918],[107.8418,29.0039],[107.8418,29.1357],[107.5781,29.2236],[107.4023,29.1797],[107.4023,28.8721],[106.875,28.7842],[106.6992,28.4766],[106.6113,28.5205],[106.6113,28.6523],[106.5234,28.7842],[106.4355,28.7842],[106.5234,28.5645],[106.3477,28.5205],[106.2598,28.8721],[105.8203,28.96],[105.7324,29.2676],[105.4688,29.3115],[105.293,29.5313],[105.7324,29.8828],[105.5566,30.1025],[105.6445,30.2783],[105.8203,30.4541],[106.2598,30.1904],[106.6113,30.3223],[106.7871,30.0146],[107.0508,30.0146],[107.4902,30.6299],[107.4023,30.7617],[107.4902,30.8496],[107.9297,30.8496],[108.1934,31.5088],[108.5449,31.6846]]]}},{"type":"Feature","id":"ning_xia","properties":{"name":"宁夏","cp":[105.9961,37.3096],"childNum":5},"geometry":{"type":"Polygon","coordinates":[[[104.3262,37.4414],[105.8203,37.793],[105.9082,38.7158],[106.3477,39.2871],[106.7871,39.375],[106.9629,38.9795],[106.5234,38.3203],[106.7871,38.1885],[107.3145,38.1006],[107.666,37.8809],[107.3145,37.6172],[107.3145,37.0898],[106.6113,37.0898],[106.6113,36.7822],[106.4355,36.5625],[106.5234,36.4746],[106.5234,36.2549],[106.875,36.123],[106.9629,35.8154],[106.6992,35.6836],[106.4355,35.6836],[106.5234,35.332],[106.3477,35.2441],[106.2598,35.4199],[106.084,35.376],[105.9961,35.4199],[106.084,35.4639],[105.9961,35.4639],[105.8203,35.5518],[105.7324,35.7275],[105.3809,35.7715],[105.293,35.9912],[105.4688,36.123],[105.2051,36.6943],[105.293,36.8262],[104.8535,37.2217],[104.5898,37.2217],[104.5898,37.4414],[104.3262,37.4414]]]}},{"type":"Feature","id":"hai_nan","properties":{"name":"海南","cp":[109.9512,19.2041],"childNum":18},"geometry":{"type":"Polygon","coordinates":[[[108.6328,19.3799],[109.0723,19.6436],[109.248,19.9512],[109.5996,20.0391],[110.0391,20.127],[110.3906,20.127],[110.5664,20.2588],[110.6543,20.2588],[111.0938,19.9512],[111.2695,19.9951],[110.6543,19.1602],[110.5664,18.6768],[110.2148,18.5889],[110.0391,18.3691],[109.8633,18.3691],[109.6875,18.1055],[108.9844,18.2813],[108.6328,18.457],[108.6328,19.3799]]]}},{"type":"Feature","id":"tai_wan","properties":{"name":"台湾","cp":[121.0254,23.5986],"childNum":1},"geometry":{"type":"Polygon","coordinates":[[[121.9043,25.0488],[121.9922,25.0049],[121.8164,24.7412],[121.9043,24.5654],[121.6406,24.0381],[121.377,23.1152],[121.0254,22.6758],[120.8496,22.0605],[120.7617,21.9287],[120.6738,22.3242],[120.2344,22.5879],[120.0586,23.0713],[120.1465,23.6865],[121.0254,25.0488],[121.5527,25.3125],[121.9043,25.0488]]]}},{"type":"Feature","id":"bei_jing","properties":{"name":"北京","cp":[116.4551,40.2539],"childNum":19},"geometry":{"type":"Polygon","coordinates":[[[117.4219,40.21],[117.334,40.1221],[117.2461,40.0781],[116.8066,39.9902],[116.8945,39.8145],[116.8945,39.6826],[116.8066,39.5947],[116.543,39.5947],[116.3672,39.4629],[116.1914,39.5947],[115.752,39.5068],[115.4883,39.6387],[115.4004,39.9463],[115.9277,40.2539],[115.752,40.5615],[116.1035,40.6055],[116.1914,40.7813],[116.4551,40.7813],[116.3672,40.9131],[116.6309,41.0449],[116.9824,40.6934],[117.4219,40.6494],[117.2461,40.5176],[117.4219,40.21]]]}},{"type":"Feature","id":"tian_jin","properties":{"name":"天津","cp":[117.4219,39.4189],"childNum":18},"geometry":{"type":"Polygon","coordinates":[[[116.8066,39.5947],[116.8945,39.6826],[117.1582,39.6387],[117.1582,39.8145],[117.2461,40.0781],[117.334,40.1221],[117.4219,40.21],[117.6855,40.0781],[117.6855,39.9902],[117.5098,39.9902],[117.5098,39.7705],[117.6855,39.5947],[117.9492,39.5947],[117.8613,39.4189],[118.0371,39.2432],[118.0371,39.1992],[117.8613,39.1113],[117.5977,38.6279],[117.2461,38.54],[116.7188,38.8037],[116.7188,38.9355],[116.8945,39.1113],[116.8066,39.5947]]]}},{"type":"Feature","id":"shang_hai","properties":{"name":"上海","cp":[121.4648,31.2891],"childNum":19},"geometry":{"type":"Polygon","coordinates":[[[120.9375,31.0254],[121.2012,31.4648],[121.377,31.5088],[121.1133,31.7285],[121.2012,31.8604],[121.9922,31.5967],[121.9043,31.1572],[121.9922,30.8057],[121.2891,30.6738],[120.9375,31.0254]]]}},{"type":"Feature","id":"xiang_gang","properties":{"name":"香港","cp":[114.2578,22.3242],"childNum":1},"geometry":{"type":"Polygon","coordinates":[[[114.6094,22.4121],[114.5215,22.1484],[114.3457,22.1484],[113.9063,22.1484],[113.8184,22.1924],[113.9063,22.4121],[114.1699,22.5439],[114.3457,22.5439],[114.4336,22.5439],[114.4336,22.4121],[114.6094,22.4121]]]}},{"type":"Feature","id":"ao_men","properties":{"name":"澳门","cp":[113.5547,22.1484],"childNum":1},"geometry":{"type":"Polygon","coordinates":[[[113.5986,22.1649],[113.6096,22.1265],[113.5547,22.11],[113.5437,22.2034],[113.5767,22.2034],[113.5986,22.1649]]]}}],"srcSize":{"left":243.4766,"top":36.4307,"width":61.6113,"height":35.4638}} -------------------------------------------------------------------------------- /data/country-codes.csv: -------------------------------------------------------------------------------- 1 | euname,modified,linked_country,iso3,iso2,grc,isonum,country,imperitive 2 | ,,Georgia,,,ABK,,Abkhazia,De Facto; Currency 3 | AFGHANISTAN,,,AFG,AF,AFG,004,Afghanistan, 4 | ,Added 26th October 2010,Finland,ALA,AX,ALA,248,Åland Islands,Postal 5 | Albania,,,ALB,AL,ALB,008,Albania, 6 | ALGERIA,,,DZA,DZ,ALG,012,Algeria, 7 | ,,United States of America,ASM,AS,AMS,016,American Samoa,Geographical 8 | ANDORRA,,,AND,AD,AND,020,Andorra, 9 | ANGOLA,,,AGO,AO,ANG,024,Angola, 10 | ,,United Kingdom,AIA,AI,ANU,660,Anguilla,Geographical; Postal; Currency; Telephone 11 | ANTIGUA AND BARBUDA,,,ATG,AG,ANT,028,Antigua & Barbuda, 12 | Argentina,,,ARG,AR,ARG,032,Argentina, 13 | Armenia,,,ARM,AM,ARM,051,Armenia, 14 | ARUBA,,Netherlands,ABW,AW,ARU,533,Aruba,Geographical; Postal; Currency; Telephone 15 | Australia,,,AUS,AU,AST,036,Australia, 16 | Austria,,,AUT,AT,AUS,040,Austria, 17 | AZERBAIJAN,,,AZE,AZ,AZE,031,Azerbaijan, 18 | BAHAMAS,,,BHS,BS,BAH,044,Bahamas, 19 | BAHRAIN,,,BHR,BH,BAR,048,Bahrain, 20 | BANGLADESH,,,BGD,BD,BAN,050,Bangladesh, 21 | Barbados,,,BRB,BB,BAB,052,Barbados, 22 | BELARUS,,,BLR,BY,BEO,112,Belarus, 23 | Belgium,,,BEL,BE,BEL,056,Belgium, 24 | BELIZE,,,BLZ,BZ,BEI,084,Belize, 25 | Benin,,,BEN,BJ,BEN,204,Benin, 26 | ,,United Kingdom,BMU,BM,BER,060,Bermuda,Geographical; Postal; Currency; Telephone 27 | BHUTAN,,,BTN,BT,BHU,064,Bhutan, 28 | BOLIVIA,,,BOL,BO,BOL,068,Bolivia, 29 | ,ISO codes added 28th Dec. 2010,Netherlands,BES,BQ,BON,535,Bonaire,Geographical; Postal; Currency; Telephone 30 | Bosnia-Herzegovina,,,BIH,BA,BOS,070,Bosnia-Herzegovina, 31 | BOTSWANA,,,BWA,BW,BOT,072,Botswana, 32 | Brazil,,,BRA,BR,BRA,076,Brazil, 33 | ,,"United Kingdom, United States of America",IOT,IO,BIO,086,British Indian Ocean Territory,Geographical; Postal; Telephone 34 | British Virgin Islands,,United Kingdom,VGB,VG,BVI,092,British Virgin Islands,Geographical; Postal; Currency; Telephone 35 | BRUNEI,,,BRN,BN,BRU,096,Brunei Darussalam, 36 | Bulgaria,,,BGR,BG,BUL,100,Bulgaria, 37 | BURKINA FASO,,,BFA,BF,BUK,854,Burkina Faso, 38 | BURUNDI,,,BDI,BI,BUU,108,Burundi, 39 | Cambodia,,,KHM,KH,CAM,116,Cambodia, 40 | Cameroon,,,CMR,CM,CAE,120,Cameroon, 41 | Canada,,,CAN,CA,CAN,124,Canada, 42 | CAPE VERDE,,,CPV,CV,CAP,132,Cape Verde Islands, 43 | ,,United Kingdom,CYM,KY,CAY,136,Cayman Islands,Geographical; Postal; Currency; Telephone 44 | "CENTRAL AFRICAN, REPUBLIC",,,CAF,CF,CEN,140,Central African Republic, 45 | Chad,,,TCD,TD,CHA,148,Chad, 46 | CHILE,,,CHL,CL,CHI,152,Chile, 47 | CHINA,,,CHN,CN,CHN,156,China, 48 | ,,Australia,CXR,CX,CHR,162,Christmas Island,Geographical 49 | ,,Australia,CCK,CC,COC,166,Cocos (Keeling) Islands,Geographical 50 | Colombia,,,COL,CO,CLO,170,Colombia, 51 | COMOROS,,,COM,KM,COM,174,Comoros, 52 | CONGO,,,COG,CG,CNG,178,Congo (Brazzaville), 53 | "CONGO, DEMOCRATIC REPUBLIC OF",,,ZAR,CD,ZAI,180,Congo (Kinshasa), 54 | COOK ISLANDS,,New Zealand,COK,CK,COO,184,Cook Islands,Geographical; Postal; Telephone 55 | Costa Rica,,,CRI,CR,COS,188,Costa Rica, 56 | Croatia,,,HRV,HR,CRO,191,Croatia, 57 | CUBA,,,CUB,CU,CUB,192,Cuba, 58 | ,ISO codes added 28th Dec. 2010,Netherlands,CUW,CW,CUR,531,Curaçao,Geographical; Postal; Currency; Telephone 59 | Cyprus,,,CYP,CY,CYP,196,Cyprus, 60 | Czech Republic,,,CZE,CZ,CZE,203,Czech Republic, 61 | Denmark,,,DNK,DK,DEN,208,Denmark, 62 | DJIBOUTI,,,DJI,DJ,DJI,262,Djibouti, 63 | DOMINIQUE,,,DMA,DM,DOI,212,Dominica, 64 | Dominican Republic,,,DOM,DO,DOM,214,Dominican Republic, 65 | EAST TIMOR,,,TLS,TL,ETI,626,East Timor, 66 | Ecuador,,,ECU,EC,ECU,218,Ecuador, 67 | EGYPT,,,EGY,EG,EGY,818,Egypt, 68 | El Salvador,,,SLV,SV,ELS,222,El Salvador, 69 | EQUATORIAL GUINEA,,,GNQ,GQ,EQA,226,Equatorial Guinea, 70 | ERITREA,,,ERI,ER,ERI,232,Eritrea, 71 | Estonia,,,EST,EE,EST,233,Estonia, 72 | ETHIOPIA,,,ETH,ET,ETH,231,Ethiopia, 73 | FAROE ISLANDS,,,FRO,FO,FAE,234,Faeroe Islands, 74 | ,,United Kingdom,FLK,FK,FAL,238,Falkland Islands,Geographical; Postal; Currency; Telephone 75 | FIJI,,,FJI,FJ,FIJ,242,Fiji, 76 | Finland,,,FIN,FI,FIN,246,Finland, 77 | France,,,FRA,FR,FRA,250,France, 78 | FRENCH GUYANA,,France,GUF,GF,FGU,254,French Guiana,Geographical; Telephone 79 | FRENCH POLYNESIA,Corrected 13th November 2010,France,PYF,PF,FPO,258,French Polynesia,Geographical; Currency; Telephone 80 | ,,France,ATF,TF,FST,260,French Southern Territories,Geographical; Postal; Telephone 81 | GABON,,,GAB,GA,GAB,266,Gabon, 82 | GAMBIA,,,GMB,GM,GAM,270,Gambia, 83 | GEORGIA,,,GEO,GE,GEO,268,Georgia, 84 | Germany,,,DEU,DE,GER,276,Germany, 85 | Ghana,,,GHA,GH,GHA,288,Ghana, 86 | GIBRALTAR,,United Kingdom,GIB,GI,GIB,292,Gibralter,Geographical; Postal; Currency; Telephone 87 | Greece,,,GRC,GR,GRE,300,Greece, 88 | GREENLAND,,Denmark,GRL,GL,GRN,304,Greenland,Geographical; Postal; Telephone 89 | GRENADA,,,GRD,GD,GRA,308,Grenada, 90 | GUADELOUPE,,France,GLP,GP,GUD,312,Guadeloupe,Geographical; Postal; Telephone 91 | ,,United States of America,GUM,GU,GUM,316,Guam,Geographical 92 | Guatemala,,,GTM,GT,GUA,320,Guatemala, 93 | ,,United Kingdom,GGY,GG,GUE,831,Guernsey,Postal 94 | Guinea,,,GIN,GN,GUI,324,Guinea, 95 | GUINEA BISSAU,,,GNB,GW,GUB,624,Guinea-Bissau, 96 | GUYANA,,,GUY,GY,GUY,328,Guyana, 97 | HAITI,,,HTI,HT,HAI,332,Haiti, 98 | HOLY SEE (VATICAN CITY STATE),,,VAT,VA,VAT,336,Holy See, 99 | Honduras,,,HND,HN,HON,340,Honduras, 100 | Hong Kong,,China,HKG,HK,HOK,344,Hong Kong,Postal; Currency; Telephone 101 | Hungary,,,HUN,HU,HUN,348,Hungary, 102 | Iceland,,,ISL,IS,ICE,352,Iceland, 103 | India,,,IND,IN,IND,356,India, 104 | INDONESIA,,,IDN,ID,INO,360,Indonesia, 105 | "IRAN, ISLAMIC REPUBLIC OF",,,IRN,IR,IRA,364,Iran, 106 | IRAQ,,,IRQ,IQ,IRQ,368,Iraq, 107 | Ireland,,,IRL,IE,IRE,372,Ireland, 108 | ,,United Kingdom,IMN,IM,ISL,833,Isle of Man,Postal 109 | Israel,,,ISR,IL,ISR,376,Israel, 110 | Italy,,,ITA,IT,ITA,380,Italy, 111 | COTE D'IVOIRE,,,CIV,CI,IVO,384,Ivory Coast, 112 | Jamaica,,,JAM,JM,JAM,388,Jamaica, 113 | Japan,,,JPN,JP,JAP,392,Japan, 114 | JERSEY,,United Kingdom,JEY,JE,JER,832,Jersey,Postal 115 | JORDAN,,,JOR,JO,JOR,400,Jordan, 116 | KAZAKHSTAN,,,KAZ,KZ,KAZ,398,Kazakhstan, 117 | Kenya,,,KEN,KE,KEN,404,Kenya, 118 | KIRIBATI,,,KIR,KI,KII,296,Kiribati, 119 | ,,Serbia,,,KOS,,Kosovo,Postal; Currency; Telephone 120 | KUWAIT,,,KWT,KW,KUW,414,Kuwait, 121 | KYRGYZSTAN,,,KGZ,KG,KIR,417,Kyrgyzstan, 122 | "LAOS, PEOPLE'S DEMOCRATIC REPUBLIC",,,LAO,LA,LAO,418,Laos, 123 | Latvia,,,LVA,LV,LAT,428,Latvia, 124 | LEBANON,,,LBN,LB,LEB,422,Lebanon, 125 | LESOTHO,,,LSO,LS,LES,426,Lesotho, 126 | LIBERIA,,,LBR,LR,LIR,430,Liberia, 127 | LIBYA,,,LBY,LY,LIB,434,Libya, 128 | LIECHTENSTEIN,,,LIE,LI,LIE,438,Liechtenstein, 129 | LITUANIA,,,LTU,LT,LIT,440,Lithuania, 130 | Luxembourg,,,LUX,LU,LUX,442,Luxembourg, 131 | MACAO,,China,MAC,MO,MCA,446,Macau,Postal; Currency; Telephone 132 | "MACEDONIA, FORMER YUGOSLAV REPUBLIC OF",,,MKD,MK,MCE,807,Macedonia, 133 | MADAGASCAR,,,MDG,MG,MAD,450,Madagascar, 134 | MALAWI,,,MWI,MW,MAW,454,Malawi, 135 | Malaysia,,,MYS,MY,MAA,458,Malaysia, 136 | MALDIVES,,,MDV,MV,MAV,462,Maldives, 137 | MALI,,,MLI,ML,MAI,466,Mali, 138 | Malta,,,MLT,MT,MAL,470,Malta, 139 | MARSHALL ISLANDS,,,MHL,MH,MAR,584,Marshall Islands, 140 | MARTINIQUE,,France,MTQ,MQ,MAN,474,Martinique,Geographical; Postal; Telephone 141 | Mauritania,,,MRT,MR,MAU,478,Mauritania, 142 | MAURITIUS,,,MUS,MU,MAT,480,Mauritius, 143 | MAYOTTE,,France,MYT,YT,MAY,175,Mayotte,Geographical; Postal; Telephone 144 | Mexico,,,MEX,MX,MEX,484,Mexico, 145 | "MICRONESIA, FEDERATED STATES OF",,,FSM,FM,MIC,583,Micronesia, 146 | "MOLDOVA, REPUBLIC OF",,,MDA,MD,MOL,498,Moldova, 147 | Monaco,,,MCO,MC,MON,492,Monaco, 148 | MONGOLIA,,,MNG,MN,MOG,496,Mongolia, 149 | Montenegro,,,MNE,ME,MOE,499,Montenegro, 150 | ,,United Kingdom,MSR,MS,MOT,500,Montserrat,Geographical; Postal; Currency; Telephone 151 | Morocco,,,MAR,MA,MOR,504,Morocco, 152 | Mozambique,,,MOZ,MZ,MOZ,508,Mozambique, 153 | Myanmar,,,MMR,MM,BUR,104,Myanmar, 154 | ,,Azerbaijan,,,NAG,,Nagorno-Karabakh,De Facto 155 | NAMIBIA,,,NAM,NA,NAM,516,Namibia, 156 | NAURU,,,NRU,NR,NAU,520,Nauru, 157 | NEPAL,,,NPL,NP,NEP,524,Nepal, 158 | Netherlands Antilles,,,ANT,AN,NAN,530,Netherlands Antilles,Legacy 159 | Netherlands,,,NLD,NL,NET,528,Netherlands, 160 | NEW CALEDONIA,,France,NCL,NC,NCA,540,New Caledonia,Geographical; Postal; Currency; Telephone 161 | NEW ZEALAND,,,NZL,NZ,NEW,554,New Zealand, 162 | Nicaragua,,,NIC,NI,NIC,558,Nicaragua, 163 | Niger,,,NER,NE,NIE,562,Niger, 164 | Nigeria,,,NGA,NG,NIG,566,Nigeria, 165 | NIUE,,,NIU,NU,NIU,570,Niue, 166 | ,,Australia,NFK,NF,NOF,574,Norfolk Island,Geographical; Telephone 167 | "KOREA, PEOPLE'S DEMOCRATIC REPUBLIC OF",,,PRK,KP,NKO,408,North Korea, 168 | ,,Cyprus,,,NCY,,Northern Cyprus,De Facto; Postal; Currency; Telephone 169 | ,,United States of America,MNP,MP,NMI,580,Northern Mariana Islands,Geographical 170 | Norway,,,NOR,NO,NOR,578,Norway, 171 | OMAN,,,OMN,OM,OMA,512,Oman, 172 | Pakistan,,,PAK,PK,PAK,586,Pakistan, 173 | PALAU,,,PLW,PW,PAL,585,Palau, 174 | PALESTINIAN OCCUPIED TERRITORY,,Israel,PSE,PS,PLA,275,Palestinian Territories, 175 | PANAMA,,,PAN,PA,PAN,591,Panama, 176 | PAPUA NEW GUINEA,,,PNG,PG,PAP,598,Papua New Guinea, 177 | PARAGUAY,,,PRY,PY,PAR,600,Paraguay, 178 | PERU,,,PER,PE,PER,604,Peru, 179 | Philippines,,,PHL,PH,PHI,608,Philippines, 180 | ,,United Kingdom,PCN,PN,PIT,612,Pitcairn Islands,Geographical; Postal; Currency; Telephone 181 | Poland,,,POL,PL,POL,616,Poland, 182 | Portugal,,,PRT,PT,POR,620,Portugal, 183 | PUERTO RICO,,United States,PRI,PR,PUE,630,Puerto Rico,Geographical 184 | ,,Somalia,,,PUN,,Puntland,De Facto 185 | QATAR,,,QAT,QA,QAT,634,Qatar, 186 | Romania,,,ROU,RO,ROM,642,Romania, 187 | "RUSSIA, FEDERATION OF",,,RUS,RU,RUS,643,Russia, 188 | RUANDA,,,RWA,RW,RWA,646,Rwanda, 189 | REUNION,,France,REU,RE,REU,638,Réunion,Geographical; Postal; Currency; Telephone 190 | ,ISO codes added 28th Dec. 2010,The Netherlands,BES,BQ,SAB,535,Saba,Geographical; Postal; Currency; Telephone 191 | ,,France,BLM,BL,STB,652,Saint Barthélemy,Geographical; Postal; Currency; Telephone 192 | SAINT KITTS AND NEVIS,,,KNA,KN,STC,659,Saint Christopher & Nevis, 193 | ,,United Kingdom,SHN,SH,STH,654,Saint Helena,Geographical; Postal; Currency; Telephone 194 | SAINT LUCIA,,,LCA,LC,STL,662,Saint Lucia, 195 | ,,France,MAF,MF,STM,663,Saint Martin,Geographical; Postal; Currency; Telephone 196 | ,,France,SPM,PM,SPM,666,Saint Pierre & Miquelon,Geographical; Postal; Currency; Telephone 197 | SAINT VINCENT AND THE GRENADINES,,,VCT,VC,STV,670,Saint Vincent & The Grenadines, 198 | SAMOA,,,WSM,WS,WSM,882,Samoa, 199 | SAINT MARINO,,,SMR,SM,SAN,674,San Marino, 200 | SAO TOME AND PRINCIPE,,,STP,ST,SAO,678,Sao Tome & Principe, 201 | SUADI ARABIA,,,SAU,SA,SAU,682,Saudi Arabia, 202 | Senegal,,,SEN,SN,SEN,686,Senegal, 203 | Serbia,,,SRB,RS,YUG,688,Serbia, 204 | SEYCHELLES,,,SYC,SC,SEY,690,Seychelles, 205 | SIERRA LEONE,,,SLE,SL,SIE,694,Sierra Leone, 206 | SINGAPORE,,,SGP,SG,SIN,702,Singapore, 207 | ,ISO codes added 28th Dec. 2010,The Netherlands,BES,BQ,STE,535,Sint Eustatius,Geographical; Postal; Currency; Telephone 208 | ,ISO codes added 28th Dec. 2010,The Netherlands,SXM,SX,SMA,534,Sint Maarten,Geographical; Postal; Currency; Telephone 209 | Slovakia,,,SVK,SK,SLO,703,Slovakia, 210 | Slovenia,,,SVN,SI,SLV,705,Slovenia, 211 | SOLOMON ISLANDS,,,SLB,SB,SOL,090,Solomon Islands, 212 | SOMALIA,,,SOM,SO,SOM,706,Somalia, 213 | ,,Somalia,SOM,SO,SOA,706,Somaliland,De Facto 214 | South Africa,,,ZAF,ZA,SAF,710,South Africa, 215 | ,,United Kingdom,SGS,GS,SGE,239,South Georgia & The South Sandwish Islands,Geographical; Postal; Currency; Telephone 216 | "KOREA, REPUBLIC OF",,,KOR,KR,SKO,418,South Korea, 217 | ,,Georgia,,,SOS,,South Ossetia,De Facto; Currency 218 | SOUTH SUDAN,Added 22nd February 2011. ISO codes added 18th August 2011.,,SSD,SS,SSU,,South Sudan, 219 | Spain,,,ESP,ES,SPA,724,Spain, 220 | SRI LANKA,,,LKA,LK,SRI,144,Sri Lanka, 221 | Sudan,,,SDN,SD,SUD,736,Sudan, 222 | SURINAM,,,SUR,SR,SUR,740,Suriname, 223 | SWAZILAND,,,SWZ,SZ,SWA,748,Swaziland, 224 | Sweden,,,SWE,SE,SWE,752,Sweden, 225 | Switzerland,,,CHE,CH,SWI,756,Switzerland, 226 | "SYRIA, ARAB REPUBLIC",,,SYR,SY,SYR,760,Syria, 227 | TAIWAN,,China,TWN,TW,TAI,158,Taiwan, 228 | TAJIKISTAN,,,TJK,TJ,TAJ,762,Tajikistan, 229 | "TANZANIA, UNITED RE UBLIC OF",,,TZA,TZ,TAN,834,Tanzania, 230 | THAILAND,,,THA,TH,THA,764,Thailand, 231 | TOGO,,,TGO,TG,TOG,768,Togo, 232 | ,,New Zealand,TKL,TK,TOK,772,Tokelau,Geographical; Postal; Telephone 233 | TONGA,,,TON,TO,TON,776,Tonga, 234 | ,,Moldova,,,TRA,,Transdniestria,De Facto 235 | TRINIDAD AND TOBAGO,,,TTO,TT,TRI,780,Trinidad & Tobago, 236 | Tunisia,,,TUN,TN,TUN,788,Tunisia, 237 | Turkey,,,TUR,TR,TUR,792,Turkey, 238 | TURKMENISTAN,,,TKM,TM,TUK,795,Turkmenistan, 239 | ,,United Kingdom,TCA,TC,TUC,796,Turks & Caicos Islands,Geographical; Postal; Currency; Telephone 240 | TUVALU,,,TUV,TV,TUV,798,Tuvalu, 241 | Uganda,,,UGA,UG,UGA,800,Uganda, 242 | Ukraine,,,UKR,UA,UKR,804,Ukraine, 243 | United Arab Emirates,,,ARE,AE,UAE,784,United Arab Emirates, 244 | United Kingdom,,,GBR,GB,UNI,826,United Kingdom, 245 | United States,,,USA,US,USA,840,United States, 246 | US VIRGIN ISLANDS,,United States of America,VIR,VI,VIR,850,United States Virgin Islands,Geographical 247 | URUGUAY,,,URY,UY,URU,858,Uruguay, 248 | UZBEKISTAN,,,UZB,UZ,UZB,860,Uzbekistan, 249 | VANUATU,,,VUT,VU,VAN,548,Vanuatu, 250 | VENEZUELA,,,VEN,VE,VEN,862,Venezuela, 251 | VIETNAM,,,VNM,VN,VIE,704,Vietnam, 252 | ,,France,WLF,WF,WAL,876,Wallis & Futuna,Geographical; Postal; Currency; Telephone 253 | WESTERN SAHARA,,Morocco,ESH,EH,WSA,732,Western Sahara,Political 254 | Yemen,,,YEM,YE,YEM,887,Yemen, 255 | ZAMBIA,,,ZMB,ZM,ZAM,894,Zambia, 256 | ZIMBABWE,,,ZWE,ZW,ZIM,716,Zimbabwe, 257 | -------------------------------------------------------------------------------- /flags.css: -------------------------------------------------------------------------------- 1 | .f16 .flag{display:inline-block;height:16px;width:16px;vertical-align:text-top;line-height:16px;background:url(images/flags/flags16.png) no-repeat;} 2 | .f16 ._African_Union{background-position:0 -16px;} 3 | .f16 ._Arab_League{background-position:0 -32px;} 4 | .f16 ._ASEAN{background-position:0 -48px;} 5 | .f16 ._CARICOM{background-position:0 -64px;} 6 | .f16 ._CIS{background-position:0 -80px;} 7 | .f16 ._Commonwealth{background-position:0 -96px;} 8 | .f16 ._England{background-position:0 -112px;} 9 | .f16 ._European_Union, .f16 .eu{background-position:0 -128px;} 10 | .f16 ._Islamic_Conference{background-position:0 -144px;} 11 | .f16 ._Kosovo{background-position:0 -160px;} 12 | .f16 ._NATO{background-position:0 -176px;} 13 | .f16 ._Northern_Cyprus{background-position:0 -192px;} 14 | .f16 ._Northern_Ireland{background-position:0 -208px;} 15 | .f16 ._Olimpic_Movement{background-position:0 -224px;} 16 | .f16 ._OPEC{background-position:0 -240px;} 17 | .f16 ._Red_Cross{background-position:0 -256px;} 18 | .f16 ._Scotland{background-position:0 -272px;} 19 | .f16 ._Somaliland{background-position:0 -288px;} 20 | .f16 ._Tibet{background-position:0 -304px;} 21 | .f16 ._United_Nations{background-position:0 -320px;} 22 | .f16 ._Wales{background-position:0 -336px;} 23 | .f16 .ad{background-position:0 -352px;} 24 | .f16 .ae{background-position:0 -368px;} 25 | .f16 .af{background-position:0 -384px;} 26 | .f16 .ag{background-position:0 -400px;} 27 | .f16 .ai{background-position:0 -416px;} 28 | .f16 .al{background-position:0 -432px;} 29 | .f16 .am{background-position:0 -448px;} 30 | .f16 .ao{background-position:0 -464px;} 31 | .f16 .aq{background-position:0 -480px;} 32 | .f16 .ar{background-position:0 -496px;} 33 | .f16 .as{background-position:0 -512px;} 34 | .f16 .at{background-position:0 -528px;} 35 | .f16 .au{background-position:0 -544px;} 36 | .f16 .aw{background-position:0 -560px;} 37 | .f16 .ax{background-position:0 -576px;} 38 | .f16 .az{background-position:0 -592px;} 39 | .f16 .ba{background-position:0 -608px;} 40 | .f16 .bb{background-position:0 -624px;} 41 | .f16 .bd{background-position:0 -640px;} 42 | .f16 .be{background-position:0 -656px;} 43 | .f16 .bf{background-position:0 -672px;} 44 | .f16 .bg{background-position:0 -688px;} 45 | .f16 .bh{background-position:0 -704px;} 46 | .f16 .bi{background-position:0 -720px;} 47 | .f16 .bj{background-position:0 -736px;} 48 | .f16 .bm{background-position:0 -752px;} 49 | .f16 .bn{background-position:0 -768px;} 50 | .f16 .bo{background-position:0 -784px;} 51 | .f16 .br{background-position:0 -800px;} 52 | .f16 .bs{background-position:0 -816px;} 53 | .f16 .bt{background-position:0 -832px;} 54 | .f16 .bw{background-position:0 -848px;} 55 | .f16 .by{background-position:0 -864px;} 56 | .f16 .bz{background-position:0 -880px;} 57 | .f16 .ca{background-position:0 -896px;} 58 | .f16 .cg{background-position:0 -912px;} 59 | .f16 .cf{background-position:0 -928px;} 60 | .f16 .cd{background-position:0 -944px;} 61 | .f16 .ch{background-position:0 -960px;} 62 | .f16 .ci{background-position:0 -976px;} 63 | .f16 .ck{background-position:0 -992px;} 64 | .f16 .cl{background-position:0 -1008px;} 65 | .f16 .cm{background-position:0 -1024px;} 66 | .f16 .cn{background-position:0 -1040px;} 67 | .f16 .co{background-position:0 -1056px;} 68 | .f16 .cr{background-position:0 -1072px;} 69 | .f16 .cu{background-position:0 -1088px;} 70 | .f16 .cv{background-position:0 -1104px;} 71 | .f16 .cy{background-position:0 -1120px;} 72 | .f16 .cz{background-position:0 -1136px;} 73 | .f16 .de{background-position:0 -1152px;} 74 | .f16 .dj{background-position:0 -1168px;} 75 | .f16 .dk{background-position:0 -1184px;} 76 | .f16 .dm{background-position:0 -1200px;} 77 | .f16 .do{background-position:0 -1216px;} 78 | .f16 .dz{background-position:0 -1232px;} 79 | .f16 .ec{background-position:0 -1248px;} 80 | .f16 .ee{background-position:0 -1264px;} 81 | .f16 .eg{background-position:0 -1280px;} 82 | .f16 .eh{background-position:0 -1296px;} 83 | .f16 .er{background-position:0 -1312px;} 84 | .f16 .es{background-position:0 -1328px;} 85 | .f16 .et{background-position:0 -1344px;} 86 | .f16 .fi{background-position:0 -1360px;} 87 | .f16 .fj{background-position:0 -1376px;} 88 | .f16 .fm{background-position:0 -1392px;} 89 | .f16 .fo{background-position:0 -1408px;} 90 | .f16 .fr{background-position:0 -1424px;} .f16 .bl, .f16 .cp, .f16 .mf, .f16 .yt{background-position:0 -1424px;} 91 | .f16 .ga{background-position:0 -1440px;} 92 | .f16 .gb{background-position:0 -1456px;} .f16 .sh{background-position:0 -1456px;} 93 | .f16 .gd{background-position:0 -1472px;} 94 | .f16 .ge{background-position:0 -1488px;} 95 | .f16 .gg{background-position:0 -1504px;} 96 | .f16 .gh{background-position:0 -1520px;} 97 | .f16 .gi{background-position:0 -1536px;} 98 | .f16 .gl{background-position:0 -1552px;} 99 | .f16 .gm{background-position:0 -1568px;} 100 | .f16 .gn{background-position:0 -1584px;} 101 | .f16 .gp{background-position:0 -1600px;} 102 | .f16 .gq{background-position:0 -1616px;} 103 | .f16 .gr{background-position:0 -1632px;} 104 | .f16 .gt{background-position:0 -1648px;} 105 | .f16 .gu{background-position:0 -1664px;} 106 | .f16 .gw{background-position:0 -1680px;} 107 | .f16 .gy{background-position:0 -1696px;} 108 | .f16 .hk{background-position:0 -1712px;} 109 | .f16 .hn{background-position:0 -1728px;} 110 | .f16 .hr{background-position:0 -1744px;} 111 | .f16 .ht{background-position:0 -1760px;} 112 | .f16 .hu{background-position:0 -1776px;} 113 | .f16 .id{background-position:0 -1792px;} 114 | .f16 .mc{background-position:0 -1792px;} 115 | .f16 .ie{background-position:0 -1808px;} 116 | .f16 .il{background-position:0 -1824px;} 117 | .f16 .im{background-position:0 -1840px;} 118 | .f16 .in{background-position:0 -1856px;} 119 | .f16 .iq{background-position:0 -1872px;} 120 | .f16 .ir{background-position:0 -1888px;} 121 | .f16 .is{background-position:0 -1904px;} 122 | .f16 .it{background-position:0 -1920px;} 123 | .f16 .je{background-position:0 -1936px;} 124 | .f16 .jm{background-position:0 -1952px;} 125 | .f16 .jo{background-position:0 -1968px;} 126 | .f16 .jp{background-position:0 -1984px;} 127 | .f16 .ke{background-position:0 -2000px;} 128 | .f16 .kg{background-position:0 -2016px;} 129 | .f16 .kh{background-position:0 -2032px;} 130 | .f16 .ki{background-position:0 -2048px;} 131 | .f16 .km{background-position:0 -2064px;} 132 | .f16 .kn{background-position:0 -2080px;} 133 | .f16 .kp{background-position:0 -2096px;} 134 | .f16 .kr{background-position:0 -2112px;} 135 | .f16 .kw{background-position:0 -2128px;} 136 | .f16 .ky{background-position:0 -2144px;} 137 | .f16 .kz{background-position:0 -2160px;} 138 | .f16 .la{background-position:0 -2176px;} 139 | .f16 .lb{background-position:0 -2192px;} 140 | .f16 .lc{background-position:0 -2208px;} 141 | .f16 .li{background-position:0 -2224px;} 142 | .f16 .lk{background-position:0 -2240px;} 143 | .f16 .lr{background-position:0 -2256px;} 144 | .f16 .ls{background-position:0 -2272px;} 145 | .f16 .lt{background-position:0 -2288px;} 146 | .f16 .lu{background-position:0 -2304px;} 147 | .f16 .lv{background-position:0 -2320px;} 148 | .f16 .ly{background-position:0 -2336px;} 149 | .f16 .ma{background-position:0 -2352px;} 150 | .f16 .md{background-position:0 -2368px;} 151 | .f16 .me{background-position:0 -2384px;} 152 | .f16 .mg{background-position:0 -2400px;} 153 | .f16 .mh{background-position:0 -2416px;} 154 | .f16 .mk{background-position:0 -2432px;} 155 | .f16 .ml{background-position:0 -2448px;} 156 | .f16 .mm{background-position:0 -2464px;} 157 | .f16 .mn{background-position:0 -2480px;} 158 | .f16 .mo{background-position:0 -2496px;} 159 | .f16 .mq{background-position:0 -2512px;} 160 | .f16 .mr{background-position:0 -2528px;} 161 | .f16 .ms{background-position:0 -2544px;} 162 | .f16 .mt{background-position:0 -2560px;} 163 | .f16 .mu{background-position:0 -2576px;} 164 | .f16 .mv{background-position:0 -2592px;} 165 | .f16 .mw{background-position:0 -2608px;} 166 | .f16 .mx{background-position:0 -2624px;} 167 | .f16 .my{background-position:0 -2640px;} 168 | .f16 .mz{background-position:0 -2656px;} 169 | .f16 .na{background-position:0 -2672px;} 170 | .f16 .nc{background-position:0 -2688px;} 171 | .f16 .ne{background-position:0 -2704px;} 172 | .f16 .ng{background-position:0 -2720px;} 173 | .f16 .ni{background-position:0 -2736px;} 174 | .f16 .nl{background-position:0 -2752px;} .f16 .bq{background-position:0 -2752px;} 175 | .f16 .no{background-position:0 -2768px;} .f16 .bv, .f16 .nq, .f16 .sj{background-position:0 -2768px;} 176 | .f16 .np{background-position:0 -2784px;} 177 | .f16 .nr{background-position:0 -2800px;} 178 | .f16 .nz{background-position:0 -2816px;} 179 | .f16 .om{background-position:0 -2832px;} 180 | .f16 .pa{background-position:0 -2848px;} 181 | .f16 .pe{background-position:0 -2864px;} 182 | .f16 .pf{background-position:0 -2880px;} 183 | .f16 .pg{background-position:0 -2896px;} 184 | .f16 .ph{background-position:0 -2912px;} 185 | .f16 .pk{background-position:0 -2928px;} 186 | .f16 .pl{background-position:0 -2944px;} 187 | .f16 .pr{background-position:0 -2960px;} 188 | .f16 .ps{background-position:0 -2976px;} 189 | .f16 .pt{background-position:0 -2992px;} 190 | .f16 .pw{background-position:0 -3008px;} 191 | .f16 .py{background-position:0 -3024px;} 192 | .f16 .qa{background-position:0 -3040px;} 193 | .f16 .re{background-position:0 -3056px;} 194 | .f16 .ro{background-position:0 -3072px;} 195 | .f16 .rs{background-position:0 -3088px;} 196 | .f16 .ru{background-position:0 -3104px;} 197 | .f16 .rw{background-position:0 -3120px;} 198 | .f16 .sa{background-position:0 -3136px;} 199 | .f16 .sb{background-position:0 -3152px;} 200 | .f16 .sc{background-position:0 -3168px;} 201 | .f16 .sd{background-position:0 -3184px;} 202 | .f16 .se{background-position:0 -3200px;} 203 | .f16 .sg{background-position:0 -3216px;} 204 | .f16 .si{background-position:0 -3232px;} 205 | .f16 .sk{background-position:0 -3248px;} 206 | .f16 .sl{background-position:0 -3264px;} 207 | .f16 .sm{background-position:0 -3280px;} 208 | .f16 .sn{background-position:0 -3296px;} 209 | .f16 .so{background-position:0 -3312px;} 210 | .f16 .sr{background-position:0 -3328px;} 211 | .f16 .st{background-position:0 -3344px;} 212 | .f16 .sv{background-position:0 -3360px;} 213 | .f16 .sy{background-position:0 -3376px;} 214 | .f16 .sz{background-position:0 -3392px;} 215 | .f16 .tc{background-position:0 -3408px;} 216 | .f16 .td{background-position:0 -3424px;} 217 | .f16 .tg{background-position:0 -3440px;} 218 | .f16 .th{background-position:0 -3456px;} 219 | .f16 .tj{background-position:0 -3472px;} 220 | .f16 .tl{background-position:0 -3488px;} 221 | .f16 .tm{background-position:0 -3504px;} 222 | .f16 .tn{background-position:0 -3520px;} 223 | .f16 .to{background-position:0 -3536px;} 224 | .f16 .tr{background-position:0 -3552px;} 225 | .f16 .tt{background-position:0 -3568px;} 226 | .f16 .tv{background-position:0 -3584px;} 227 | .f16 .tw{background-position:0 -3600px;} 228 | .f16 .tz{background-position:0 -3616px;} 229 | .f16 .ua{background-position:0 -3632px;} 230 | .f16 .ug{background-position:0 -3648px;} 231 | .f16 .us{background-position:0 -3664px;} 232 | .f16 .uy{background-position:0 -3680px;} 233 | .f16 .uz{background-position:0 -3696px;} 234 | .f16 .va{background-position:0 -3712px;} 235 | .f16 .vc{background-position:0 -3728px;} 236 | .f16 .ve{background-position:0 -3744px;} 237 | .f16 .vg{background-position:0 -3760px;} 238 | .f16 .vi{background-position:0 -3776px;} 239 | .f16 .vn{background-position:0 -3792px;} 240 | .f16 .vu{background-position:0 -3808px;} 241 | .f16 .ws{background-position:0 -3824px;} 242 | .f16 .ye{background-position:0 -3840px;} 243 | .f16 .za{background-position:0 -3856px;} 244 | .f16 .zm{background-position:0 -3872px;} 245 | .f16 .zw{background-position:0 -3888px;} 246 | .f16 .sx{background-position:0 -3904px;} 247 | .f16 .cw{background-position:0 -3920px;} 248 | .f16 .ss{background-position:0 -3936px;} 249 | .f16 .o1{background-position:0 -3952px;} -------------------------------------------------------------------------------- /fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Norse-Mapcons'; 3 | src:url('fonts/Norse-Mapcons.eot?m6qc03'); 4 | src:url('fonts/Norse-Mapcons.eot?#iefixm6qc03') format('embedded-opentype'), 5 | url('fonts/Norse-Mapcons.woff?m6qc03') format('woff'), 6 | url('fonts/Norse-Mapcons.ttf?m6qc03') format('truetype'), 7 | url('fonts/Norse-Mapcons.svg?m6qc03#Norse-Mapcons') format('svg'); 8 | font-weight: normal; 9 | font-style: normal; 10 | } 11 | 12 | [class^="icon-"], [class*=" icon-"] { 13 | font-family: 'Norse-Mapcons'; 14 | speak: none; 15 | font-style: normal; 16 | font-weight: normal; 17 | font-variant: normal; 18 | text-transform: none; 19 | line-height: 1; 20 | 21 | /* Better Font Rendering =========== */ 22 | -webkit-font-smoothing: antialiased; 23 | -moz-osx-font-smoothing: grayscale; 24 | } 25 | 26 | .icon-country:before { 27 | content: "\61"; 28 | } 29 | .icon-number:before { 30 | content: "\62"; 31 | } 32 | .icon-military:before { 33 | content: "\64"; 34 | } 35 | .icon-close:before { 36 | content: "\63"; 37 | } 38 | .icon-play:before { 39 | content: "\65"; 40 | } 41 | .icon-pause:before { 42 | content: "\66"; 43 | } 44 | .icon-info:before { 45 | content: "\67"; 46 | } 47 | .icon-open:before { 48 | content: "\68"; 49 | } 50 | .icon-closed:before { 51 | content: "\69"; 52 | } 53 | .icon-threattype:before { 54 | content: "\6a"; 55 | } 56 | .icon-down:before { 57 | content: "\6b"; 58 | } 59 | .icon-one:before { 60 | content: "\6c"; 61 | } 62 | .icon-five:before { 63 | content: "\6d"; 64 | } 65 | .icon-ten:before { 66 | content: "\6e"; 67 | } 68 | .icon-twentyfive:before { 69 | content: "\6f"; 70 | } 71 | .icon-onehundred:before { 72 | content: "\70"; 73 | } 74 | .icon-twohundred:before { 75 | content: "\71"; 76 | } 77 | .icon-fivehundred:before { 78 | content: "\72"; 79 | } 80 | .icon-googleplus:before { 81 | content: "\73"; 82 | } 83 | .icon-facebook:before { 84 | content: "\74"; 85 | } 86 | .icon-linkedin:before { 87 | content: "\75"; 88 | } 89 | .icon-youtube:before { 90 | content: "\76"; 91 | } 92 | .icon-twitter:before { 93 | content: "\77"; 94 | } 95 | -------------------------------------------------------------------------------- /fonts/Norse-Mapcons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LubyRuffy/livemapdemo/b7454daea7ce3ea8359b4b6fcb78bd017d10140d/fonts/Norse-Mapcons.woff -------------------------------------------------------------------------------- /images/DarkNoiseBackground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LubyRuffy/livemapdemo/b7454daea7ce3ea8359b4b6fcb78bd017d10140d/images/DarkNoiseBackground.png -------------------------------------------------------------------------------- /images/flags/flags16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LubyRuffy/livemapdemo/b7454daea7ce3ea8359b4b6fcb78bd017d10140d/images/flags/flags16.png -------------------------------------------------------------------------------- /images/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LubyRuffy/livemapdemo/b7454daea7ce3ea8359b4b6fcb78bd017d10140d/images/loading.gif -------------------------------------------------------------------------------- /images/norse-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LubyRuffy/livemapdemo/b7454daea7ce3ea8359b4b6fcb78bd017d10140d/images/norse-white.png -------------------------------------------------------------------------------- /images/unknown-poly.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LubyRuffy/livemapdemo/b7454daea7ce3ea8359b4b6fcb78bd017d10140d/images/unknown-poly.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Norse - IPViking Live 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 |

Loading...

14 |
15 |
16 | 17 | 18 | 19 |
20 | 21 |
22 | 23 |
24 |

25 | 26 | 攻击来源 27 |

28 |
29 |
30 |
31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 |
国家
45 |
46 |
47 | 48 |
49 | 50 |
51 |

52 | 53 | 攻击目标 54 |

55 |
56 |
57 |
58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 |
国家
72 |
73 |
74 | 75 |
76 | 77 |
78 |

79 | 80 | 攻击类型 81 |

82 |
83 |
84 | 85 |
86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 |
类型
100 |
101 |
102 | 103 |
104 | 105 |
106 |

107 | 108 | 实时攻击 109 |

110 |
111 |
112 |
113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 |
攻击者目标行为
时间位置IP服务器IP服务器位置攻击类型
139 |
140 |
141 |
142 |
143 | 144 |
145 |
146 | 147 |
148 |
149 |
150 | 151 |
152 |
153 | 154 |
155 | 156 |
157 |
158 |
159 |

Norse Dark Intelligence

160 |

161 | Every second, Norse collects and analyzes live threat 162 | intelligence from darknets in hundreds of locations in 163 | over 40 countries. The attacks shown are based on a 164 | small subset of live flows against the Norse honeypot 165 | infrastructure, representing actual worldwide cyber 166 | attacks by bad actors. At a glance, one can see which 167 | countries are aggressors or targets at the moment, using 168 | which type of attacks (services-ports). 169 |

170 | 171 |

172 | Hovering over the Attack Origins, 173 | Attack Targets, or 174 | Attack Types will 175 | highlight just the attacks emanating from that country 176 | or over that service-port respectively. Hovering over 177 | any bubble on the map, will highlight only the attacks 178 | from that location and type. Press s 179 | to toggle table sizes. 180 |

181 | 182 |

183 | Norse exposes its threat intelligence via 184 | high-performance, machine-readable APIs in a variety of 185 | forms. Norse also provides products and solutions that 186 | assist organizations in protecting and mitigating cyber 187 | attacks. 188 |

189 | 190 |

191 | For more information, please contact: 192 | inquiry@norse-corp.com 193 |

194 | 195 | 202 |
203 | 204 |
205 |
206 |

Each particle represents an attack

207 |

208 |
209 |
210 |

Attack origins are grouped into clusters

211 |

212 | 213 | 214 | 215 |

216 |
217 |
218 |

Countries are shaded in as they're attacked

219 |

220 | 221 | 222 | 223 | 224 | 225 |

226 |
227 |
228 | 229 | 243 |
244 |
245 |
246 |
247 |
248 |

Message Dialog

249 |
250 |
251 | 252 | 253 |
254 |
255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | -------------------------------------------------------------------------------- /ipviking.css: -------------------------------------------------------------------------------- 1 | @import url(http://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800); 2 | @import url(http://fonts.googleapis.com/css?family=Oswald:400,300,700); 3 | 4 | body { 5 | overflow: hidden; 6 | margin: 0; 7 | color: white; 8 | background: url(images/DarkNoiseBackground.png); 9 | font-family: "Oswald", "Open Sans", sans-serif; 10 | } 11 | 12 | ol { 13 | list-style-type: none; 14 | margin-left: -2.0em; 15 | } 16 | 17 | td { 18 | font-family: "Open Sans", "Oswald", sans-serif; 19 | font-weight: 400; 20 | } 21 | 22 | 23 | th { 24 | font-weight: normal; 25 | } 26 | 27 | h1, h2, h3, h4 { 28 | font-family: "Oswald", "Open Sans", sans-serif; 29 | } 30 | 31 | #drawer { 32 | position: absolute; 33 | top: 48px; 34 | right: 6px; 35 | z-index: 100; 36 | height: 385px; 37 | width: 595px; 38 | } 39 | 40 | .blue-bg { 41 | background: rgb(0, 78, 176); 42 | background: transparent\9; 43 | background-color: rgb(0, 78, 176, 0.95); 44 | border-radius: 4px; 45 | border: 1px solid rgba(0, 78, 176); 46 | border: 1px solid rgba(0, 78, 176, 0.95); 47 | -webkit-background-clip: padding-box; /* for Safari */ 48 | background-clip: padding-box; /* for IE9+, Firefox 4+, Opera, Chrome */ 49 | } 50 | 51 | #drawer-content { 52 | height: 100%; 53 | float: right; 54 | overflow: hidden; 55 | } 56 | 57 | #drawer-inner a, 58 | #drawer-content.info-btn { 59 | text-decoration: underline; 60 | color: #fff; 61 | } 62 | 63 | #drawer-inner a:hover, 64 | #drawer-content .info-btn:hover { 65 | color: rgb(20, 180, 255); 66 | } 67 | 68 | #drawer-inner { 69 | padding: 0 1em; 70 | font-size: 11px; 71 | font-family: "Open Sans", "Oswald", sans-serif; 72 | font-weight: 300; 73 | line-height: 13px; 74 | } 75 | 76 | #drawer-content h1 { 77 | margin-top: 5px; 78 | font-size: 24px; 79 | font-family: "Open Sans", "Oswald", sans-serif; 80 | font-weight: 300; 81 | line-height: 30px; 82 | } 83 | 84 | #drawer-left { 85 | float: left; 86 | width: 60%; 87 | } 88 | 89 | .table-ref { 90 | font-family: "Oswald", "Open Sans"; 91 | font-weight: bold; 92 | text-transform: uppercase; 93 | font-size: 0.9em; 94 | } 95 | 96 | /* 97 | This has awful performance... 98 | #drawer-content .footer { 99 | width: 480px; 100 | position: absolute; 101 | bottom: 0; 102 | } 103 | */ 104 | 105 | nav { 106 | /* background-color: rgba(0, 140, 240, 0.95);*/ 107 | background: linear-gradient(rgba(0, 138, 255, 0.5), 108 | rgba(0, 150, 255, 0.5)), 109 | rgba(0, 0, 0, 0.8); 110 | float: left; 111 | width: 40px; 112 | border-bottom-left-radius: 6px; 113 | } 114 | 115 | nav ul { 116 | list-style-type: none; 117 | margin: 0 0 0 -2.4em; 118 | } 119 | 120 | nav ul li { 121 | margin: 0.2em; 122 | font-size: 1.4em; 123 | text-align: center; 124 | } 125 | 126 | nav ul li a { 127 | display: block; 128 | } 129 | 130 | nav ul li a:visited, a:link { 131 | color: white; 132 | text-decoration: none; 133 | } 134 | 135 | nav ul li a:hover { 136 | color: white; 137 | border-top-color: white; 138 | text-decoration: underline; 139 | } 140 | 141 | #content { 142 | width: 100%; 143 | opacity: 0; 144 | } 145 | 146 | #display-label-container { 147 | width: 100%; 148 | text-align: center; 149 | position: absolute; 150 | z-index: 6; 151 | text-shadow: -1px -1px 0 #000, 152 | 1px -1px 0 #000, 153 | -1px 1px 0 #000, 154 | 1px 1px 0 #000; 155 | } 156 | 157 | #top-line { 158 | width: 100%; 159 | background-color: rgb(1, 73, 128); 160 | height: 5px; 161 | } 162 | 163 | #logo { 164 | position: absolute; 165 | left: 6px; 166 | top: 12px; 167 | z-index: 100; 168 | } 169 | 170 | #loading { 171 | position: absolute; 172 | right: 4em; 173 | bottom: 1em; 174 | } 175 | 176 | #info { 177 | position: absolute; 178 | right: 20em; 179 | top: 1em; 180 | } 181 | 182 | .overlay { 183 | position: absolute; 184 | top: 0; 185 | left: 0; 186 | right: 0; 187 | z-index: 4; 188 | } 189 | 190 | .icon { 191 | width: 1em; 192 | } 193 | 194 | .buffer { 195 | visibility: hidden; 196 | } 197 | 198 | .shadow { 199 | -moz-box-shadow: 0 0 5px 5px rgb(40, 50, 80); 200 | -webkit-box-shadow: 0 0 5px 5px rgb(40, 50, 80); 201 | box-shadow: 0 0 5px 5px rgb(40, 50, 80); 202 | } 203 | 204 | .box { 205 | position: absolute; 206 | z-index: 20; 207 | 1px -1px 0 #000, 208 | -1px 1px 0 #000, 209 | 1px 1px 0 #000; 210 | } 211 | 212 | .gray-bg { 213 | background: rgb(51,51,51); 214 | background: transparent\9; 215 | background: rgba(51,51,51,0.5); 216 | border-radius: 4px; 217 | border: 1px solid rgba(51, 51, 51); 218 | border: 1px solid rgba(51, 51, 51, 0.5); 219 | -webkit-background-clip: padding-box; /* for Safari */ 220 | background-clip: padding-box; /* for IE9+, Firefox 4+, Opera, Chrome */ 221 | } 222 | 223 | .black-solid { 224 | background-color: rgba(10, 20, 30, 0.8); 225 | border: thin solid rgb(0, 180, 240); 226 | border-bottom-right-radius: 6px; 227 | border-bottom-left-radius: 6px; 228 | -webkit-box-shadow: 0 0 3px 1px rgb(0, 120, 240); 229 | -moz-box-shadow: 0 0 3px 1px rgb(0, 120, 240); 230 | box-shadow: 0 0 3px 1px rgb(0, 120, 240); 231 | } 232 | 233 | .table-container { 234 | z-index: -2; 235 | } 236 | 237 | /* 238 | .data table th { 239 | color: rgb(45, 255, 254); 240 | } 241 | */ 242 | 243 | .data { 244 | width: 180px; 245 | } 246 | 247 | .data table tr { 248 | line-height: 18px; 249 | text-align: left; 250 | } 251 | 252 | .data table td, 253 | .data table th { 254 | font-size: 12px; 255 | } 256 | 257 | .data table th { 258 | font-size: 13px; 259 | font-family: "Open Sans Bold", "Oswald", sans-serif; 260 | font-weight: 700; 261 | text-transform: uppercase; 262 | } 263 | 264 | .data table th [class^="icon-"], .data table th [class*=" icon-"] { 265 | font-size: 16px; 266 | } 267 | 268 | .data table td span.numeric { 269 | font-size: 10px; 270 | font-family: "Open Sans Light", "Oswald", sans-serif; 271 | font-weight: 300; 272 | } 273 | 274 | .data .flag { 275 | margin-right: 20px; 276 | height: 1.0em; 277 | } 278 | 279 | .data .numeric { 280 | margin-right: 10px; 281 | } 282 | 283 | .data .icon-number { 284 | margin-right: 8px; 285 | } 286 | 287 | .data colgroup .bar-col { width: 0; } 288 | .data colgroup .total-count { width: 2.6em; } 289 | .data colgroup .data-label-small { width: 1.6em; } 290 | .data colgroup .data-label { width: 10em; } 291 | .data colgroup .port-label { width: 2.8em; } 292 | 293 | 294 | .data tr.row:hover { 295 | background-color: #0c2b4a; 296 | } 297 | 298 | .data table .bar { 299 | position: absolute; 300 | height: 20px; 301 | margin-top: -10px; 302 | background-color: #0c2b4a; 303 | z-index: -1; 304 | border-radius: 3px; 305 | max-width: 98%; 306 | } 307 | 308 | .data table tr td:nth-child(2), 309 | .data table tr th:nth-child(2) { 310 | text-align: right; 311 | padding-right: 0.4em; 312 | } 313 | 314 | .port-circle { 315 | font-size: 1.8em; 316 | text-align: center; 317 | line-height: 0.5em; 318 | } 319 | 320 | .table-header { 321 | text-align: center; 322 | color: rgb(40, 255, 255); 323 | color: rgb(255, 255, 255); 324 | text-transform: uppercase; 325 | border-top-right-radius: 6px; 326 | border-top-left-radius: 6px; 327 | margin-bottom: 4px; 328 | } 329 | 330 | .table-header h1 { 331 | margin: 0.4em 0.8em; 332 | font-family: "Open Sans", "Oswald", sans-serif; 333 | font-weight: 400; 334 | font-size: 16px; 335 | text-align: left; 336 | } 337 | 338 | .top-left { 339 | top: 72px; 340 | left: 6px; 341 | } 342 | 343 | .bottom { 344 | bottom: 6px; 345 | } 346 | 347 | .top-right { 348 | right: 6px; 349 | top: 48px; 350 | } 351 | 352 | .bottom-right { 353 | bottom: 50px; 354 | right: 6px; 355 | } 356 | 357 | .info-controls { 358 | position: absolute; 359 | top: 6px; 360 | right: 6px; 361 | z-index: 20; 362 | } 363 | 364 | .info-controls .icon-close { 365 | font-size: 14px; 366 | } 367 | 368 | .info-controls > div { 369 | float: right; 370 | width: 86px; 371 | height: 34px; 372 | } 373 | 374 | .info-controls > div:first-child { 375 | margin-left: 6px; 376 | } 377 | 378 | .controls { 379 | display: block; 380 | text-align: center; 381 | list-style: none; 382 | padding: 0; 383 | margin: 0; 384 | } 385 | 386 | .controls:hover { 387 | color: #00a6ff; 388 | cursor: pointer; 389 | } 390 | 391 | .controls > span { 392 | display: inline-block; 393 | line-height: 34px; 394 | } 395 | 396 | .information { 397 | display: block; 398 | text-align: center; 399 | list-style: none; 400 | padding: 0; 401 | margin: 0; 402 | } 403 | 404 | .information:hover { 405 | color: #00a6ff; 406 | cursor: pointer; 407 | } 408 | 409 | .information > span { 410 | line-height: 34px; 411 | display: inline-block; 412 | } 413 | 414 | .world { 415 | stroke: #555; 416 | stroke-linejoin: round; 417 | } 418 | 419 | .tick { 420 | stroke: white; 421 | } 422 | 423 | /* The data console */ 424 | #console { 425 | left: 6px; 426 | bottom: 32px; 427 | pointer-events: none; 428 | padding: 6px 12px; 429 | } 430 | 431 | #console .table-header h1 { 432 | margin: 0; 433 | min-width: 156px; 434 | } 435 | 436 | #console .table-header { 437 | margin-bottom: 0; 438 | } 439 | 440 | #console table { 441 | font-size: 10px; 442 | font-family: "Open Sans Normal", "Oswald", sans-serif; 443 | font-weight: 400; 444 | line-height: 12px; 445 | border-collapse: collapse; 446 | } 447 | 448 | #console table td, 449 | #console table th { 450 | text-shadow: none; 451 | padding-right: 20px; 452 | } 453 | 454 | #console table td:last-child, 455 | #console table th:last-child { 456 | padding-right: 0px; 457 | } 458 | 459 | #console table tr.first-level { 460 | font-size: 12px; 461 | font-family: "Open Sans Bold", "Oswald", sans-serif; 462 | font-weight: 700; 463 | line-height: 16px; 464 | text-align: left; 465 | text-transform: uppercase; 466 | } 467 | 468 | #console table tr.second-level { 469 | font-size: 10px; 470 | font-family: "Open Sans Bold", "Oswald", sans-serif; 471 | font-weight: 700; 472 | line-height: 12px; 473 | text-align: left; 474 | padding-bottom: 0.2em; 475 | font-weight: light; 476 | text-transform: uppercase; 477 | } 478 | 479 | #console table tr.second-level th { 480 | font-weight: light !important; 481 | } 482 | 483 | #console colgroup col.left-border { 484 | padding-left: 0.5em; 485 | } 486 | 487 | #console table span.overflow { 488 | display: block; 489 | overflow: hidden; 490 | text-overflow: ellipsis; 491 | height: 1.4em; 492 | } 493 | 494 | #console colgroup col.timestamp-col { width: 11em; } 495 | #console colgroup col.location-col { width: 130px; } 496 | #console colgroup col.attacker-org-col { width: 160px; } 497 | #console colgroup col.attacker-ip-col { width: 98px; } 498 | #console colgroup col.service-col { width: 70px; } 499 | #console colgroup col.port-col { width: 30px; } 500 | 501 | a.toggle { 502 | color: rgb(55, 116, 172); 503 | pointer-events: all; 504 | } 505 | 506 | #rate-graph { 507 | z-index: 20; 508 | position: absolute; 509 | left: 6px; 510 | bottom: 6px; 511 | width: 100%; 512 | height: 20; 513 | } 514 | 515 | #drawer { 516 | display: none; 517 | } 518 | 519 | #drawer .social-media { 520 | list-style: none; 521 | padding: 0; 522 | margin: 0; 523 | } 524 | 525 | #drawer .social-media li { 526 | display: inline-block; 527 | margin-right: 35px; 528 | } 529 | 530 | #drawer .social-media li:last-child { 531 | margin-right: 0px; 532 | } 533 | 534 | #drawer .social-media a { 535 | text-decoration: none; 536 | font-size: 11px; 537 | font-family: "Open Sans Bold", "Oswald", sans-serif; 538 | font-weight: 700; 539 | } 540 | 541 | /* TODO -- sort these */ 542 | .attacker { 543 | color: rgb(214, 39, 40); 544 | } 545 | 546 | .target { 547 | color: rgb(31, 119, 180); 548 | } 549 | 550 | 551 | /* LEGEND */ 552 | 553 | #legend-container { 554 | float: left; 555 | width: 26%; 556 | margin-left: 10%; 557 | margin-top: 52px; 558 | padding-left: 10px; 559 | background: rgb(0,84,190); /* Old browsers */ 560 | background: -moz-linear-gradient(left, rgba(0,84,190,1) 0px, rgba(0,84,190,1) 3px, rgba(0,78,176,1) 3px, rgba(0,78,176,1) 3px, rgba(0,78,176,1) 100%); /* FF3.6+ */ 561 | background: -webkit-gradient(linear, left top, right top, color-stop(0px,rgba(0,84,190,1)), color-stop(3px,rgba(0,84,190,1)), color-stop(3px,rgba(0,78,176,1)), color-stop(3px,rgba(0,78,176,1)), color-stop(100%,rgba(0,78,176,1))); /* Chrome,Safari4+ */ 562 | background: -webkit-linear-gradient(left, rgba(0,84,190,1) 0px,rgba(0,84,190,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 100%); /* Chrome10+,Safari5.1+ */ 563 | background: -o-linear-gradient(left, rgba(0,84,190,1) 0px,rgba(0,84,190,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 100%); /* Opera 11.10+ */ 564 | background: -ms-linear-gradient(left, rgba(0,84,190,1) 0px,rgba(0,84,190,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 100%); /* IE10+ */ 565 | background: linear-gradient(to right, rgba(0,84,190,1) 0px,rgba(0,84,190,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 3px,rgba(0,78,176,1) 100%); /* W3C */ 566 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#0054be', endColorstr='#004eb0',GradientType=1 ); /* IE6-9 */ 567 | } 568 | 569 | #legend-container h4 { 570 | margin: 0; 571 | font-size: 9px; 572 | margin-bottom: 20px; 573 | font-family: "Open Sans Bold", "Oswald", sans-serif; 574 | font-weight: 400; 575 | line-height: 11px; 576 | text-align: left; 577 | } 578 | 579 | #legend > div { 580 | margin: auto 0.5%; 581 | text-align: left; 582 | } 583 | 584 | #legend ul { 585 | list-style-type: none; 586 | margin-left: -2em; 587 | } 588 | 589 | #legend .clusters ul > li { 590 | display: inline-block; 591 | margin: auto 0.8em; 592 | } 593 | 594 | #legend .country-colors ul > li { 595 | display: inline-block; 596 | margin: auto 0.2em; 597 | width: 1.2em; 598 | } 599 | 600 | #particle-legend > p { 601 | margin-left: 40px; 602 | } 603 | 604 | #origin-legend > p { 605 | margin-left: 15px; 606 | } 607 | 608 | #country-legend > p { 609 | margin-left: 5px; 610 | } 611 | 612 | #origin-legend p span { 613 | margin-right: 4px; 614 | } 615 | 616 | #origin-legend p .icon-one { 617 | font-size: 20px; 618 | padding-top: 12px; 619 | margin-right: ; 620 | } 621 | 622 | #origin-legend p .icon-ten { 623 | padding-top: 8px; 624 | font-size: 24px; 625 | } 626 | 627 | #origin-legend p .icon-twohundred { 628 | font-size: 32px; 629 | } 630 | 631 | h4 > span { 632 | margin-right: 5px; 633 | float: left; 634 | margin-top: 1px; 635 | } 636 | 637 | h4 > p { 638 | display: inline-block; 639 | width: 85%; 640 | margin: 0px; 641 | } 642 | 643 | #country-legend p [class^="icon-"], #country-legend p [class*=" icon-"] { 644 | font-size: 20px; 645 | } 646 | 647 | footer { 648 | width: 30%; 649 | float: right; 650 | font-size: 8px; 651 | font-family: "Open Sans", "Oswald", sans-serif; 652 | line-height: 10px; 653 | margin-top: 10px; 654 | } 655 | 656 | #events-data tr td:first-child { 657 | white-space: nowrap; 658 | } 659 | 660 | #message-panel { 661 | display: none; 662 | position: absolute; 663 | margin-left: auto; 664 | margin-right: auto; 665 | left: 0; 666 | right: 0; 667 | top: 300px; 668 | width: 600px; 669 | } 670 | 671 | #message-container { 672 | position: relative; 673 | min-height: 100px; 674 | padding: 10px; 675 | text-align: center; 676 | vertical-align: middle; 677 | } 678 | 679 | #message-container span { 680 | display: inline-block; 681 | vertical-align: middle ; 682 | } 683 | 684 | #close-button { 685 | position: absolute; 686 | width: 100px; 687 | left: 250px; 688 | bottom: 20px; 689 | height: 25px; 690 | color: white; 691 | border-radius: 3px; 692 | } 693 | 694 | #social-icons { 695 | position: absolute; 696 | height: 36px; 697 | width: 180px; 698 | bottom: 6px; 699 | right: 6px; 700 | font-size: 20px; 701 | line-height: 36px; 702 | text-align: center; 703 | z-index: 20; 704 | } 705 | 706 | #social-icons ul { 707 | list-style: none; 708 | padding: 0; 709 | margin: 0; 710 | } 711 | 712 | #social-icons li { 713 | display: inline-block; 714 | } 715 | 716 | #social-icons a { 717 | display: inline-block; 718 | cursor: pointer; 719 | } 720 | 721 | #social-icons a:visited { 722 | color: white; 723 | } 724 | 725 | #unknown-icon { 726 | position: absolute; 727 | width: 36px; 728 | height: 36px; 729 | opacity: 0.6; 730 | } 731 | -------------------------------------------------------------------------------- /ipviking.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | // http://isc.sans.org 3 | 4 | var approvedDomains = ['norse-corp.com', 'mitsui.com', 'mbsd.jp']; 5 | if (top.location != self.location && approvedDomains.indexOf(top.location.hostname) === -1) { 6 | top.location = self.location.href 7 | } 8 | 9 | var refreshSeconds = 60 * 60 * 6; // 6 hours 10 | setTimeout("location.reload()", refreshSeconds * 1000); 11 | 12 | function showMessage (message) { 13 | document.getElementById('message-text').innerHTML = message; 14 | document.getElementById('message-panel').style.display = "block"; 15 | } 16 | 17 | function hideMessage () { 18 | document.getElementById('message-panel').style.display = 'none'; 19 | } 20 | 21 | (function(window) { 22 | var VSN = "1.1"; 23 | 24 | var isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; 25 | 26 | /* 27 | if(!isChrome) { 28 | showMessage("The IPViking digital attack map only supports the Google Chrome browser."); 29 | return; 30 | } 31 | */ 32 | 33 | var settings = { 34 | // The data properties to parse into numbers 35 | numberProps: ["latitude", "longitude", "latitude2", "longitude2"], 36 | // Flash this color as statistics udpate 37 | triggerColor: "red", 38 | // Range text down to this opacity 39 | minTextOpacity: 0.35, 40 | // Begin dropping attacks after this number 41 | maxAttacks: 100, 42 | radius: 5, 43 | countryColor: d3.scale.log() 44 | .domain([1, 1200]) 45 | .range([d3.rgb(30, 30, 30), d3.rgb(30, 65, 140)]), 46 | tableBarWidth: d3.scale.log() 47 | .domain([1, 500]) 48 | .range([1, 130]), 49 | 50 | // Layout settings 51 | linkAnchor: false, 52 | linkSiblings: false, 53 | 54 | // Table Rows 55 | topTableRows: 10, 56 | portTableRows: 8, 57 | consoleTableRows: 8, 58 | pruneInterval: 3600, 59 | dataPruneInterval: 60, 60 | 61 | // Websocket settings 62 | wsHost: "ws://103.28.11.231:8085/", 63 | psk: "echo-protocol", 64 | //wsHost: "ws://64.19.78.244:443/", 65 | //psk: "18c989796c61724d4661b019f2779848dd69ae62", 66 | wsTimeout: 30000 67 | }; 68 | 69 | /* 70 | * HTML Interface 71 | */ 72 | d3.selectAll(".vsn").text(VSN); 73 | 74 | var timestampedData = []; 75 | 76 | function prune () { 77 | // using the lodash library, where _.select implements binary search to find start of range 78 | // in logarithmic time 79 | 80 | var now = new Date().getTime() / 1000; 81 | 82 | for (var i in timestampedData) { 83 | if (timestampedData[i].pruneTS > now) { 84 | break; 85 | } 86 | } 87 | 88 | var expiredData = []; 89 | 90 | if (i > 0) { 91 | var expiredData = timestampedData.splice(0, i); 92 | } 93 | 94 | for (var n = 0; n < expiredData.length; n++) { 95 | // todo: //statsManager.remove(timestampData[n]); 96 | for (var model in linkModels) { 97 | linkModels[model].remove(expiredData[n]); 98 | } 99 | } 100 | } 101 | 102 | var displayLabel = { 103 | // Label for displaying general info 104 | elt: d3.select("#display-label"), 105 | 106 | set: function(text) { 107 | this.elt.text(text); 108 | }, 109 | 110 | clear: function() { 111 | this.elt.text(""); 112 | } 113 | } 114 | 115 | if (!window.chrome) { 116 | displayLabel.set("Too slow? Try Chrome."); 117 | } 118 | 119 | d3.selectAll(".info-btn").on("click", function() { 120 | d3.event.preventDefault(); 121 | var drawerContent = d3.select("#drawer"); 122 | if (drawerContent.style("display") === "none") { 123 | drawerContent 124 | .transition() 125 | .style("display", "block"); 126 | 127 | d3.selectAll(".info-btn").classed("blue-bg", true); 128 | d3.selectAll(".info-btn").classed("gray-bg", false); 129 | d3.selectAll(".info-text").classed('icon-info', false); 130 | d3.selectAll(".info-text").classed('icon-close', true); 131 | } else { 132 | drawerContent 133 | .transition() 134 | .style("display", "none"); 135 | d3.selectAll(".info-btn").classed("gray-bg", true); 136 | d3.selectAll(".info-btn").classed("blue-bg", false); 137 | d3.selectAll(".info-text").classed('icon-info', true); 138 | d3.selectAll(".info-text").classed('icon-close', false); 139 | } 140 | }); 141 | 142 | var loadingToggle = (function() { 143 | // Toggle for the loading html state 144 | var loading = true; 145 | 146 | return function() { 147 | if (loading) { 148 | d3.select("#content") 149 | .transition() 150 | .duration(1000) 151 | .style("opacity", 1); 152 | 153 | d3.select("#loading") 154 | .transition() 155 | .duration(1000) 156 | .style("opacity", 0); 157 | } else { 158 | d3.select("#content").style("opacity", 0); 159 | d3.select("#loading") 160 | .transition() 161 | .duration(1000) 162 | .style("opacity", 1); 163 | } 164 | } 165 | })(); 166 | loadingToggle(); 167 | 168 | /* 169 | * Variable definitions 170 | */ 171 | 172 | // Listen for .toggles 173 | (function() { 174 | var toggles = d3.selectAll(".toggle"); 175 | var data = toggles[0] 176 | .map(function(elt) { return d3.select(elt.getAttribute("data-target")); }); 177 | 178 | toggles 179 | .data(data) 180 | .on("click", function(d) { 181 | d3.event.preventDefault(); 182 | if (d.style("display") === "none") { 183 | d.style("display", "block"); 184 | } else { 185 | d.style("display", "none"); 186 | } 187 | }); 188 | })(); 189 | 190 | 191 | // Set up the map in d3 192 | var width = window.innerWidth, 193 | height = window.innerHeight; 194 | 195 | // Project from latlng to pixel coords 196 | var projection = d3.geo.mercator() 197 | .scale(width / 8.5) 198 | .translate([width / 2, height / 1.7]); 199 | 200 | // Draw geojson to svg path using the projection 201 | var path = d3.geo.path().projection(projection); 202 | 203 | // The svg -- our blank canvas 204 | var svg = d3.select("#content").append("svg") 205 | .attr("class", "overlay") 206 | .attr("width", width) 207 | .attr("height", height); 208 | 209 | svg.append("defs") 210 | .append("filter") 211 | .attr("id", "blur") 212 | .append("feGaussianBlur") 213 | .attr("stdDeviation", 2); 214 | 215 | 216 | // Attacks are added to the .attacks svg group and based on data 217 | var node = svg.selectAll(".node"), 218 | link = svg.selectAll(".link"); 219 | 220 | // Cluster on target city 221 | var _clusters = d3.map(); 222 | 223 | var colorizer = d3.scale.category20(); 224 | // Mapping of ports to properties 225 | var ports; 226 | 227 | 228 | /************** 229 | * Internal API 230 | */ 231 | 232 | function spanWrap(content, classes) { 233 | // Returns the content wrapped in the span 234 | return '' + 235 | content + '' 236 | } 237 | 238 | function dist(x1, y1, x2, y2) { 239 | // Returns the distance between two points 240 | return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)); 241 | } 242 | 243 | function rgbaString(c, a) { 244 | // Helper to get the color as an rgba string 245 | return "rgba(" + c.r + "," + c.g + "," + c.b + "," + a + ")"; 246 | } 247 | 248 | function parsePorts(rawPorts) { 249 | // Given the csv list of ports, process it 250 | var ports = []; 251 | for (var i = 0; i < rawPorts.length; ++i) { 252 | var port = parseInt(rawPorts[i].port); 253 | if (port in ports) { 254 | ports[port] = ports[port] + ", " + rawPorts[i].service; 255 | } else { 256 | ports[port] = rawPorts[i].service; 257 | } 258 | } 259 | 260 | // Fix certain port strings 261 | ports[80] = "http"; 262 | return ports; 263 | } 264 | 265 | var getID = (function() { 266 | // Generate unique enough IDs 267 | var i = 0; 268 | return function() { 269 | return i++; 270 | } 271 | })(); 272 | 273 | 274 | function flagPath(iso) { 275 | // Return the path to the flag for the given countrycode 276 | if (iso === "O1") { 277 | return "images/militarywhite.svg"; 278 | } else { 279 | return "images/flags/" + iso + ".png"; 280 | } 281 | } 282 | 283 | function flagTag(iso) { 284 | return ''; 285 | } 286 | 287 | function isNumber(n) { 288 | // Returns true if n is a number 289 | return !isNaN(parseFloat(n)) && isFinite(n); 290 | } 291 | 292 | var particler = function() { 293 | // Returns a function that will generate colored particles 294 | var particle = new Image(), 295 | tempFileCanvas = d3.select("#content") 296 | .append("canvas") 297 | .attr("class", "buffer") 298 | .node(); 299 | 300 | particle.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAAB3RJTUUH1wQUCC4hoGmo9QAACvlJREFUaN69mltz00gQhS3NSCMlNjEmBYTi//8zCipUsIMd6zKytA/fctKMDITArh5ctqxLX06fvsxkiz84sizLsizPc74sFotpmvSZHPO/fnLxb8jwbNH1yZc8z8dx1HedT+Q7nU6LxWIcxz+U+zkKIC7CSYEsy7z3CDoMQ5ZlRVFwXiJO0zRNE7eM4zgMA2dQ5g+dkD0dKlKA9xVFYZVJjouLixhj13V5nnvvh2GY+wQd+MQnz9DE/VL0PM/zPHfOIX2e50VROOecc4KKvb4sS+yti8uyxPZnH44m2OUZCmS/tDqPFmZkeL1MQBrH0XtPMKAGpkXz0+mUZRkQUgzIe1w8DIN89UcKIJNzTqIvFgvvPX7QgWeKorBBoovHcYwxEiGCO0eMcRxHzlur931v1X4+hJDMGl74wd15npdl6b333kt67/00TUALbhXSsL2FYlEU6GZlBYFzhX/PA5bap2mSlJiKoIRqnHOWSefPEdNbqPDX6XSKMSqK2raVJlmWxRjx0i+j4owC2Iy3OudkJ8wplsTMNishMZ/EQIzxLEdxPfIh9ziOfd8TJ1xAtPR9/3sQEjMgeoIQ+IS/rI1FsvoSQkCZoiiUB6wfEj/zk8gRjKXJb3gAmPIsvQ/E6xpodB7x0oFIEOSIVM7IzHNcgZk8z2V4PN80zU90cHMFMLa40jlnDQ+QEo+BK8WuTDtnYfTUeRsVymXOObETj/pJTLs5eybIqetaNrbJSxgTz6iekwm4KymfcC/PgUx1XhcTcsitQutsQPsfxYDgpACw4chfmNM+V8WFrlceSCg//3ZYpuJpMcayLJXRkJ53zV2RJqayLCV0CIHXz6Uvy9JSEJaG2rEu71NgiLJsoSqWm+d1xYmA9KPy1idCCPryss4Iu1YfQUtqKxPrU9UEcaxqIqlw9QruGoahqqrj8SirJT5MPUDVJb+HEJS2FJGYWXGpUkKxS8QrPEIINmSVW9Q8JCWjJVwZmzhB86QMe1SAHC5PIRPS2/hDQ8mErDr4qfDI87yqKhUROkRuSQ/knKNVSDokgkG1WRLNLmFPHq0vFvpoKCvK8IjOT8tIhNA4jqfTyZZGArfVR5/iJesf6anM/Z0CiC6BhAFRSpKVrfRiUoku26OwrTgQRbaUDkIOr7CZDu9Rn8r51gl+Xn5KepuA8IllcVQVxpCbJM2VIYSiKIhCTsYYZWZyH84pikJZDKfJD+ouuq6TAN9BiFOErGgbR8sDokUuQAEMz/U8AcygQ1EUIQRbWsuHCKca21JnUucpEriYnluN6KMCtimR35VWLQywq3DPi8uyBHVlWVZVdXFxgSZ84UZ5RnDni3NO9lbehZGtmcdvh0j5OwiJsM5WyDYY8LtKbs5776uqEk29evWqLMvT6XR5eVkUxeFw2O12VMvg2znXtq0tGdCnKAphjDmArfnAcIwR9WKM/3pAQoj15QEZWHAkdv23Q967vLy8uLgoy3Kz2SyXy7quh2EIIVRVdTgc8jxfr9dVVbVty4tVCGF7Acb6wfbNakgEHingbZmu65I2yprfVhaQj/c+xrharW5ubrquy7JstVqFENbrtXOO4KOQXi6XwzB0XSfixvzee25E+qR5SHp/Tcf+ZReroi13bXE2r91VYClkKb+ur6+dc5vNBlagrQkhfPjwIcZYVdV6vd7v93QFIYSu6wAVwYCNLc/YQQY6E5aPtZCClackxYbQb2shEZS4CApqmubq6ur9+/dXV1ebzQaVNpvNp0+fQghv377tuq7ruhhj27bOORCvx1oRbfjKUaqg7GU+qW9t6WcLdFsO2WYf2rm+vq7rOoRQ1/Visbi5uXn37h2RsN1uMeput/v48WPf90lGR435oJeEYMeSSJhkYn8WbbpHYWS7MGUJuJnhwjRNq9Xq9evXb968Wa/XL1++xDlwy+Fw2O/3x+NRhY1NzDKnJVBbF3HX2dHdY5Kn57DMxeRD/47msNNZWtjj8fj169emaZxzNHFgtyxL6Gi1Wq3Xa6omSNOWusloUVRh7Xh+hGWjk0OZQonWjmPtpEAFRQhhuVyu1+sXL16IzsWV2IJ8V9c1OtgGRaKLQ+2AI/F8OgK0aUu4tJaw/Y0tnsmyIQQywHK5jDFut1tO1nVd1/XpdNrtdnd3dw8PD1++fNlut23bQqxaLpgPXZK/ZLL5LPlMTwxCxJ5iBpXKKsoV1k3T3N7eAp6+76uq+vz5M5VFjJHYZcLVdd0wDIfDwU61kh5F1Z7QO4eQvdhLVwmq3Mw0BfNohA9tM4gdx/H+/h6VLi8vYTpofhgGVGrbFg+M41jXddu2h8NhGAZCjrfbUicZYdi0o6Hvd9Uor6/rGolV9CsYLOWrU9PYEMAg+tXV1TRN+/3ee9/3/d3d3f39fdd1+/1+t9vt9/tpmo7HY9/3TdMQ+sgkZVQLqRGzIYfaWFP/OiUjiif1E+ggiSU3L8NdVKZnkYACbdviE+S7vb09HA4xRtYBGMUJLZzRSpSdoEBo8LUI81EB8aYaK+KdVCVq0joKdZH3XpYAVE3TnE4nPImZeU3btg8PD/v9/uHhoe/7vu9ZfZKftfInFAmxMpDeJSM+BjExoKrV8kDbtmJrbhOx4ge7bkda3W63fd8z4lwsFoRE0zQxRhKLTM6N3GtNru/yhu0NVcM+lhJaehnHkWU51UVIbFMbGb5pGgJGRE711jRNURS4247cEJ1QAUKiBMwHvm3SFIw5T7mq9PLYkYEKNXusc4mUxM12aqnq1RZOmj0JD8Qo0iAxtbTY3brCsr7tGLV6qwYATz52ZCoKkvWvZJBvl+JoyWkDtAKgZS+WNmwxoyqSF2N7WJi320Gdxbc1h1ydzOecxdZ8iijkAPF5eaeBuCKShb1pmsC90II+ElEYw1GS2C7JKBhY/MOHybKaS4Z7Wp5IloEBlbykqU5ShijvyNH2EJmIxe13lYl2wUpxP78mnY3aVVQ7N7fBZLt+HqSpt6UO7K0tBQAMw1s40Y5ZrrScI/yIPW20pAokwADlyGGjmSdqIJ4sVkuNLMsge5toVThoTduuzUjDJBKQQaxgG+LUA8liMNdpWde+TIW0TSvJqpEFhq0oiYpkxAm4bXeulAz6bUgkhV26xKSaW3lRDCv8KJhsF6JKi4QvhsG0IEosJJRj16TsUVHTtq3sTdCf2XCR/C6KQrshtEY2jiNlT9LvayBpuxPbIp4tg20LZXsDhTVSIr3Cw5LVz1YpbQrTdIl4UAqz5SrWFaLsrDyZLFmEWCa1a/fyUtd1mnlZMnjSQrcoT/NX2VXtTmJjMECVYafCtqwSThTcyaIY+lAXC0WqWH+00no++wrrdpJhk4Dd6mNlVadi14UksY1CywpIzLs0SVBo/XzzSvaj3SrIJ+gDJHKFXKk1qGT9Yr7fw2puvye9mLZ8UGsklcVvbzlDPrvJgCi33ki2HSSCzsPANuzCJ+gCZvKJ8saf7pmr69qKqMlFCEGTYPU9lr4SFrLVmBRQTrCuG4ZB8/e/sOlPyx/ahjOvPuZbl4TDZAsZqGCI2zTNHG/EwNM3nj112yUdpkZdli5ZTTrLcfNhjga6yW4i9TR/Z8/cL73BpC0ZoWm+WZalYpEmTpSf5AdVfr9km7+z8dWOr9XKnN18OUf/Wf+oyn9KvD5n3+icXpTUYIwkDc+rhiRR2KbEVqzP3rz7zL3TZ+s/NRJ2LR4IKSUlLc7/unf6iQfZw3pARLn4D46/4IEklOfZ92xN+rd2r/8DebSckAm1i/EAAAAASUVORK5CYII="; 301 | 302 | tempFileCanvas.width = 64; 303 | tempFileCanvas.height = 64; 304 | 305 | return function (r, g, b, a) { 306 | var imgCtx = tempFileCanvas.getContext("2d"), 307 | imgData, i; 308 | 309 | imgCtx.drawImage(particle, 0, 0); 310 | 311 | //if(particle.width > self.innerWidth){particle.width=self.innerWidth;} if(particle.width < 1){particle.width=1;} 312 | //if(particle.height > self.innerHeight){particle.height=self.innerHeight;} if(particle.height < 1){particle.height=1;} 313 | imgData = imgCtx.getImageData(2, 2,64,64); 314 | 315 | //imgData = imgCtx.getImageData(0, 0, particle.width, particle.height); 316 | 317 | i = imgData.data.length; 318 | while((i -= 4) > -1) { 319 | imgData.data[i + 3] = imgData.data[i] * a; 320 | if (imgData.data[i + 3]) { 321 | imgData.data[i] = r; 322 | imgData.data[i + 1] = g; 323 | imgData.data[i + 2] = b; 324 | } 325 | } 326 | 327 | imgCtx.putImageData(imgData, 0, 0); 328 | return tempFileCanvas; 329 | } 330 | }(); 331 | 332 | var nodeModel = { 333 | /* 334 | * Provides an API for managing the various force layout nodes 335 | * 336 | * Node Types: 337 | * - Attack Nodes {type: attack} 338 | * - Target Nodes {type: target} 339 | * - Anchor Nodes, ie City {type: anchor} 340 | */ 341 | 342 | // Configuration 343 | linkSiblings: true, 344 | linkAnchor: false, 345 | target: true, 346 | interval: 50, 347 | pathLength: 15, 348 | targetMaxAge: 200, 349 | scaleTargetVel: d3.scale.log().domain([1, 40]).range([40, 100]), 350 | 351 | // Constants 352 | ATTACKS: "attacks", 353 | TARGETS: "targets", 354 | ANCHORS: "anchors", 355 | 356 | lastPrune: new Date().getTime() / 1000, 357 | 358 | // The list of nodes, shared with the force layout 359 | nodes: undefined, 360 | // The list of links, shared with the force layout 361 | links: undefined, 362 | 363 | // Force layout to make the elements move correctly 364 | force: d3.layout.force() 365 | .size([width, height]) 366 | .friction(0.25) 367 | .gravity(0) 368 | .charge(-10) 369 | .chargeDistance(50) 370 | .linkDistance(15) 371 | .linkStrength(function(d) { return d.linkStrength || 0.5; }), 372 | 373 | prune: function () { 374 | var now = new Date().getTime() / 1000; 375 | 376 | if (now - this.lastPrune > 10) { 377 | this.lastPrune = now; 378 | 379 | for (var i in this.nodes) { 380 | if (this.nodes[i].pruneTS > now) { 381 | if (i > 0) { 382 | this.nodes.splice(0, i); 383 | } 384 | break; 385 | } 386 | } 387 | 388 | for (var i in this.links) { 389 | if (this.links[i].pruneTS > now) { 390 | if (i > 0) { 391 | this.links.splice(0, i); 392 | } 393 | break; 394 | } 395 | } 396 | } 397 | }, 398 | 399 | get: function(type) { 400 | return this.nodes.filter(function(n) { return n.type === type; }); 401 | }, 402 | 403 | _mapKey: function(d) { 404 | return d.city + d.latitude + d.longitude; 405 | }, 406 | 407 | _remove: function(n, j) { 408 | for (var i = 0; i < this.links.length; i++) { 409 | if (this.links[i].source.id === n.id || 410 | this.links[i].target.id === n.id) { 411 | this.links.splice(i--, 1); 412 | } 413 | } 414 | 415 | if (typeof j !== 'undefined') this.nodes.splice(j, 1); 416 | 417 | // Remove a node, and its associated links 418 | for (var i = 0; i < this.nodes.length; i++) { 419 | if (n.id === this.nodes[i].id) { 420 | this.nodes.splice(i--, 1); 421 | } 422 | } 423 | 424 | }, 425 | 426 | _shift: function(type) { 427 | for (var i = 0; i < this.nodes.length; i++) { 428 | if (this.nodes[i].type === type) { 429 | this._remove(this.nodes[i], i); 430 | break; 431 | } 432 | } 433 | }, 434 | 435 | _getsertAnchorFor: function(attack) { 436 | // Get the anchor for the given node, inserting it if its not present 437 | var key = this._mapKey(attack), 438 | anchor = this.nodes.filter(function(n) { return n.key === key; })[0]; 439 | 440 | if ( anchor ) { 441 | return anchor; 442 | } else { 443 | var newAnchor = { 444 | id: getID(), 445 | key: key, 446 | type: this.ANCHORS, 447 | x: attack.cx, 448 | y: attack.cy, 449 | cx: attack.cx, 450 | cy: attack.cy, 451 | country: attack.country, 452 | city: attack.city, 453 | fixed: true, 454 | pruneTS: (new Date()).getTime() / 1000 + settings.dataPruneInterval 455 | } 456 | this.nodes.push(newAnchor); 457 | return newAnchor; 458 | } 459 | }, 460 | 461 | pushAttack: function(attack) { 462 | /* 463 | * Push a new Attack 464 | * Nodes are inserted at the source location and linked to an anchor 465 | * centered at this source, and all of the adjacent nodes. Links 466 | * are stronger to nodes of the same type. 467 | */ 468 | // Clear out old nodes 469 | while (this.get(this.ATTACKS).length > 50) { 470 | this._shift(this.ATTACKS); 471 | } 472 | if (this.linkSiblings) { 473 | var key = this._mapKey(attack), 474 | that = this; 475 | this.nodes.forEach(function(n) { 476 | if ( that._mapKey(n) === key ) { 477 | that.links.push({ 478 | source: n, 479 | target: attack, 480 | pruneTS: (new Date()).getTime() / 1000 + settings.dataPruneInterval, 481 | linkStrength: n.service === attack.service ? 0.5 : 0.25}); 482 | } 483 | }); 484 | } 485 | 486 | // Anchor 487 | var anchor = this._getsertAnchorFor(attack); 488 | if (this.linkAnchor) { 489 | this.links.push({source: anchor, target: attack, linkStrength: 1.0}); 490 | } 491 | 492 | // Target 493 | if (this.target) { 494 | var initialVelocity = -0.0001; 495 | var target = { 496 | type: this.TARGETS, 497 | age: 0, 498 | path: [], 499 | h: dist(attack.x, attack.y, attack.targetX, attack.targetY), 500 | id: getID(), 501 | x: attack.x, 502 | y: attack.y, 503 | cx: attack.targetX, 504 | cy: attack.targetY, 505 | startX: attack.x, 506 | startY: attack.y, 507 | city: attack.city2, 508 | country: attack.country2, 509 | theta: Math.atan((attack.targetY - attack.y) / 510 | (attack.targetX - attack.x)), 511 | 512 | service: attack.service, 513 | pruneTS: (new Date()).getTime() / 1000 + settings.dataPruneInterval 514 | } 515 | // this.links.push({source: this._getsertAnchorFor(target), 516 | // target: target, linkStrength: 1.0}); 517 | this.nodes.push(target); 518 | } 519 | 520 | // Decorate and add the attack node 521 | attack.type = this.ATTACKS; 522 | attack.age = 0; 523 | this.nodes.push(attack); 524 | 525 | // TODO - is this necessary?! 526 | this.force.start(); 527 | }, 528 | 529 | step: function() { 530 | // Step the simulation 531 | this.nodes.forEach(function (n) { 532 | n.age++; 533 | }); 534 | 535 | this.get(this.TARGETS) 536 | .filter(function(t) { 537 | return t.age > this.targetMaxAge || 538 | "arrivalAge" in t && t["arrivalAge"] + 40 < t.age; }, this) 539 | .forEach(function (t) { 540 | this._remove(t); 541 | }, this); 542 | }, 543 | 544 | start: function() { 545 | // Start the layout 546 | var that = this; 547 | 548 | // Initialize the array references 549 | this.nodes = []; 550 | this.links = []; 551 | this.force 552 | .nodes(this.nodes) 553 | .links(this.links) 554 | .on("tick", (function() { 555 | //var targetTrack; 556 | 557 | return function(e) { 558 | // Tick the force layout 559 | that.step(); 560 | that.get(that.ATTACKS).forEach(function(d) { 561 | var scale = 0.1; 562 | d.x += scale * (d.cx - d.x) * e.alpha; 563 | d.y += scale * (d.cy - d.y) * e.alpha; }); 564 | 565 | that.get(that.TARGETS).forEach(function(d) { 566 | //DEBUGGING 567 | // if (!targetTrack) targetTrack = d.id; 568 | // Update the target's path 569 | d.path.unshift({x: d.x, y: d.y}); 570 | if (d.path.length > that.pathLength) 571 | d.path.pop(); 572 | 573 | if (d.arrivalAge) { 574 | d.fixed = true; 575 | } else { 576 | var travelled = dist(d.x, d.y, d.startX, d.startY), 577 | //v = (Math.sqrt(travelled * 50) + 180) * e.alpha, 578 | v = that.scaleTargetVel(d.age) * e.alpha, 579 | toTarget = dist(d.cx, d.cy, d.x, d.y); 580 | 581 | if (v <= toTarget) { 582 | var theta = Math.atan2(d.cy - d.y, d.cx - d.x); 583 | //r = v / d.h; 584 | d.x += v * Math.cos(theta); 585 | d.y += v * Math.sin(theta); 586 | } else { 587 | //debugger; 588 | // Arrived at target 589 | d.x = d.cx; 590 | d.y = d.cy; 591 | d.arrivalAge = d.age; 592 | } 593 | } 594 | }); 595 | that.force.resume(); 596 | } 597 | })()) 598 | .start(); 599 | 600 | // Prevent the alpha from 'cooling' to 0 601 | d3.timer(this.force.resume); 602 | } 603 | } 604 | 605 | // An abstract model for caching and querying city <=> city links 606 | var LinksModel = { 607 | // {ORIGINCOUNTRY: {ORIGINCITY: {TRGTCOUNTRY: {TRGTCOUNTRY: {DPORT: COUNT}}}}} 608 | // Created in via .extend: _links: {}, 609 | // {COUNTRY: {CITY: {latitude: LAT, longitude: LON}}} 610 | _locs: {}, 611 | 612 | insertLink: function(origin, target, port) { 613 | if (!(origin.country in this._links)) { 614 | this._links[origin.country] = {}; 615 | } 616 | 617 | if (!(origin.city in this._links[origin.country])) { 618 | this._links[origin.country][origin.city] = {}; 619 | } 620 | 621 | var originLinks = this._links[origin.country][origin.city]; 622 | if (!(target.country in originLinks)) { 623 | originLinks[target.country] = {}; 624 | } 625 | 626 | if (!(target.city in originLinks[target.country])) { 627 | originLinks[target.country][target.city] = {}; 628 | } 629 | 630 | var targetLinks = originLinks[target.country][target.city] 631 | if (!(port in targetLinks)) { 632 | targetLinks[port] = 1; 633 | } else { 634 | targetLinks[port] = targetLinks[port] + 1; 635 | } 636 | }, 637 | 638 | removeLink: function(origin, target, port) { 639 | var link1 = this._links[origin.country]; 640 | 641 | if (!link1) return 642 | 643 | var link2 = this._links[origin.country][origin.city]; 644 | 645 | if (!link2) return 646 | 647 | var target1 = link2[target.country]; 648 | 649 | if (!target1) return 650 | 651 | var target2 = link2[target.country][target.city] 652 | 653 | if (!target2) return 654 | 655 | if (target2[port] > 1) { 656 | target2[port]--; 657 | } else if (target2[port] !== undefined){ 658 | delete target2[port]; 659 | } 660 | }, 661 | 662 | insertLoc: function(loc) { 663 | if (!(loc.country in this._locs)) { 664 | this._locs[loc.country] = {} 665 | } 666 | 667 | if (!(loc.city in this._locs)) { 668 | this._locs[loc.country][loc.city] = 669 | {latitude: loc.latitude, longitude: loc.longitude}; 670 | } 671 | }, 672 | 673 | removeLoc: function(loc, origin, target, port) { 674 | var link1 = this._links[origin.country]; 675 | 676 | if (!link1) return 677 | 678 | var link2 = this._links[origin.country][origin.city]; 679 | 680 | if (!link2) return 681 | 682 | var target1 = link2[target.country]; 683 | 684 | if (!target1) return 685 | 686 | var target2 = link2[target.country][target.city] 687 | 688 | if (!target2) return 689 | 690 | if (!target2[port]) { 691 | delete this._links[origin.country][origin.city]; 692 | delete this._locs[loc.country][loc.city] 693 | } 694 | }, 695 | 696 | _distanceBetween: function(pt1, pt2) { 697 | return Math.sqrt(Math.pow(pt1[0] - pt2[0], 2) + 698 | Math.pow(pt1[1] - pt2[1], 2)); 699 | }, 700 | 701 | getCity: function(country, city) { 702 | if (country in this._locs && city in this._locs[country] ) { 703 | var loc = this._locs[country][city], 704 | pt = projection([loc.longitude, loc.latitude]), 705 | info = { 706 | country: country, 707 | city: city, 708 | latitude: loc.latitude, 709 | longitude: loc.longitude, 710 | pt: pt}; 711 | 712 | if (country in this._links && city in this._links[country]) { 713 | info.counts = this._links[country][city]; 714 | } 715 | 716 | return info; 717 | } 718 | }, 719 | 720 | getCities: function() { 721 | // Returns list of all cities 722 | var cities = []; 723 | for (var country in this._locs) { 724 | for (var city in this._locs[country]) { 725 | cities.push(this.getCity(country, city)); 726 | } 727 | } 728 | return cities; 729 | }, 730 | 731 | getCountry: function(country) { 732 | var cities = []; 733 | for (var city in this._links[country] || {}) { 734 | cities.push(this.getCity(country, city)); 735 | } 736 | return cities; 737 | }, 738 | 739 | pixelsFromNearest: function(pt) { 740 | // Returns the pixels from the nearest source 741 | var closest; 742 | for (var country in this._links) { 743 | for (var city in this._links[country]) { 744 | var info = this.getCity(country, city); 745 | 746 | if (info) { 747 | var distance = this._distanceBetween(pt, info.pt); 748 | if (!closest || distance < closest.distance) { 749 | info.distance = distance; 750 | closest = info; 751 | } 752 | } 753 | } 754 | } 755 | return closest 756 | }, 757 | 758 | total: function (counts) { 759 | // Total up a counts array, recursive 760 | if (isNumber(counts)) { 761 | return counts; 762 | } else { 763 | var sum = 0; 764 | for (var key in counts) { 765 | sum += this.total(counts[key]); 766 | } 767 | return sum; 768 | } 769 | }, 770 | 771 | cityToLinks: function(city, strokeOrigin, strokeTarget) { 772 | if (!city) return []; 773 | 774 | var links = []; 775 | for (var country in city.counts) { 776 | if (!city.counts[country]) continue; 777 | for (var cityKey in city.counts[country]) { 778 | var info = this.getCity(country, cityKey), 779 | counts = city.counts[country][cityKey]; 780 | 781 | if (!info || !counts || !Object.keys(counts).length) continue; 782 | 783 | for (var service in counts) { 784 | var r = circleScale(counts[service]), 785 | color = colorizer(service), 786 | source = { x: city.pt[0], y: city.pt[1], r: r }, 787 | target = { x: info.pt[0], y: info.pt[1], r: r }; 788 | 789 | if (strokeTarget) { 790 | source.strokeStyle = color; 791 | } else { 792 | source.fillStyle = color; 793 | } 794 | 795 | if (strokeOrigin) { 796 | target.strokeStyle = color; 797 | } else { 798 | target.fillStyle = color; 799 | } 800 | 801 | links.push({ 802 | count: counts[service], 803 | source: source, 804 | target: target, 805 | width: lineScale(counts[service]), 806 | color: color 807 | }); 808 | } 809 | } 810 | } 811 | return links.sort(function(l1, l2) { return l2.count - l1.count; }); 812 | }, 813 | 814 | dPortLinks: function(service) { 815 | var links = [] 816 | for (var sourceCountry in this._links) { 817 | for (var sourceCity in this._links[sourceCountry]) { 818 | var s = this.getCity(sourceCountry, sourceCity); 819 | for (var targetCountry in s.counts) { 820 | for (var targetCity in s.counts[targetCountry]) { 821 | var t = this.getCity(targetCountry, targetCity); 822 | for (var targetservice in s.counts[targetCountry][targetCity]) { 823 | var c = s.counts[targetCountry][targetCity][targetservice]; 824 | if (service && service === targetservice) { 825 | links.push({ 826 | count: c, 827 | source: s, 828 | target: t, 829 | service: service 830 | }); 831 | } 832 | } 833 | } 834 | } 835 | } 836 | } 837 | return links; 838 | }, 839 | 840 | extend: function(o) { 841 | o.__proto__ = this; 842 | o._links = {}; 843 | return o; 844 | } 845 | }; 846 | 847 | // Set up the link models, one for origins, and one for targets 848 | var linkModels = { 849 | origins: LinksModel.extend({ 850 | insert: function(d) { 851 | this.insertLink( 852 | {country: d.country, city: d.city}, 853 | {country: d.country2, city: d.city2}, 854 | d.service); 855 | 856 | this.insertLoc( 857 | {country: d.country, 858 | city: d.city, 859 | latitude: d.latitude, 860 | longitude: d.longitude}); 861 | }, 862 | remove: function(d) { 863 | this.removeLink( 864 | {country: d.country, city: d.city}, 865 | {country: d.country2, city: d.city2}, 866 | d.service); 867 | 868 | this.removeLoc( 869 | {country: d.country, 870 | city: d.city, 871 | latitude: d.latitude, 872 | longitude: d.longitude}, {country: d.country, city: d.city}, 873 | {country: d.country2, city: d.city2}, 874 | d.service); 875 | } 876 | }), 877 | 878 | targets: LinksModel.extend({ 879 | insert: function(d) { 880 | this.insertLink( 881 | {country: d.country2, city: d.city2}, 882 | {country: d.country, city: d.city}, 883 | d.service); 884 | 885 | this.insertLoc( 886 | {country: d.country2, 887 | city: d.city2, 888 | latitude: d.latitude2, 889 | longitude: d.longitude2}); 890 | }, 891 | remove: function(d) { 892 | this.removeLink( 893 | {country: d.country2, city: d.city2}, 894 | {country: d.country, city: d.city}, 895 | d.service); 896 | 897 | this.removeLoc( 898 | {country: d.country2, 899 | city: d.city2, 900 | latitude: d.latitude2, 901 | longitude: d.longitude2}, {country: d.country2, city: d.city2}, 902 | {country: d.country, city: d.city}, 903 | d.service); 904 | } 905 | }) 906 | } 907 | 908 | var countryModel = { 909 | // The raw list of data 910 | _raw: undefined, 911 | _iso2: undefined, 912 | _iso3: undefined, 913 | _countries: undefined, 914 | 915 | push: function(country) { 916 | // Push a new country 917 | this._raw.push(country); 918 | if (country.iso2) this._iso2[country.iso2] = country; 919 | if (country.iso3) this._iso3[country.iso3] = country; 920 | if (country.country) this._countries[country.country] = country; 921 | }, 922 | 923 | set: function(raw) { 924 | this._raw = []; 925 | this._iso2 = {}; 926 | this._iso3 = {}; 927 | this._countries = {}; 928 | for (var i = 0; i < raw.length; i++) { this.push(raw[i]); }; 929 | }, 930 | 931 | getByIso2: function(iso2) { 932 | return this._iso2[iso2.toUpperCase()]; 933 | }, 934 | 935 | getByIso3: function(iso3) { 936 | return this._iso3[iso3.toUpperCase()]; 937 | }, 938 | 939 | getByCountry: function(country) { 940 | return this._countries[country]; 941 | } 942 | } 943 | 944 | /* 945 | * painter handles rendering to the canvas 946 | */ 947 | 948 | // Prepare canvas and buffer 949 | var canvas = d3.select("#content").append("canvas") 950 | .text("This browser doesn't support Canvas elements") 951 | .attr("id", "visible-canvas") 952 | .attr("class", "overlay") 953 | .attr("width", width) 954 | .attr("height", height) 955 | 956 | var bufCanvas = d3.select("#content").append("canvas") 957 | .attr("class", "buffer overlay") 958 | .attr("width", width) 959 | .attr("height", height); 960 | 961 | // Allows for consistent scaling of drawn elements 962 | var logScale = d3.scale.log() 963 | .domain([1, 200]) 964 | .range([1, 10]); 965 | 966 | 967 | var lineScale = function(x) { return logScale(x) }; 968 | var circleScale = function(x) { return Math.ceil(1.4 * logScale(x)) }; 969 | var colorScale = (function() { 970 | var log = d3.scale.log() 971 | .domain([1, 600]) 972 | .range([1, 100]); 973 | return function(v) { 974 | return log(v); 975 | } 976 | })(); 977 | 978 | var painter = { 979 | // The various drawings 980 | drawings: { 981 | // Draw the attack nodes 982 | nodes: { 983 | // The visible nodes 984 | active: true, 985 | nodeModel: nodeModel, 986 | // Canvas composition: "lighter", "darker", ... 987 | compositeOperation: undefined, 988 | 989 | getRadius: function(d) { 990 | // Given a node, return the radius 991 | var growthEnd = 60, growthMax = 80, 992 | growthStep = growthMax / growthEnd, 993 | shrinkEnd = 120, shrinkMin = 20, 994 | shrinkStep = (growthMax - shrinkMin) / (shrinkEnd - growthEnd); 995 | 996 | if (d.age >= 0 && d.age < growthEnd) { 997 | return growthStep * d.age; 998 | } else if (d.age < shrinkEnd) { 999 | return growthMax - shrinkStep * (d.age - growthEnd); 1000 | } else { 1001 | return shrinkMin; 1002 | } 1003 | }, 1004 | 1005 | draw: function(context) { 1006 | nodeModel.prune(); 1007 | 1008 | if (this.compositeOperation) { 1009 | context.globalCompositeOperation = this.compositeOperation; 1010 | } 1011 | 1012 | var that = this; 1013 | nodeModel.get(nodeModel.ATTACKS) 1014 | .forEach(function(n) { 1015 | var c = d3.rgb(colorizer(n.service)), 1016 | r = that.getRadius(n); 1017 | context.drawImage(particler(c.r, c.g, c.b, 1), 1018 | n.x - r / 2, n.y - r / 2, r, r); 1019 | }); 1020 | 1021 | } 1022 | }, 1023 | 1024 | // Draw new node pings 1025 | pings: { 1026 | active: true, 1027 | order: -1, 1028 | duration: 80, 1029 | scaleRadius: d3.scale.linear().domain([1, 80]).range([1, 48]), 1030 | scaleOpacity: d3.scale.linear().domain([1, 80]).range([1, 0]), 1031 | draw: function(context) { 1032 | var pi = Math.PI; 1033 | for (var i = 0; i < nodeModel.nodes.length; i++) { 1034 | var n = nodeModel.nodes[i]; 1035 | if (n.type === nodeModel.ATTACKS && n.age < this.duration) { 1036 | context.globalAlpha = this.scaleOpacity(n.age); 1037 | context.strokeStyle = colorizer(n.service); 1038 | context.lineWidth = 3; 1039 | context.beginPath(); 1040 | context.arc(n.x, n.y, this.scaleRadius(n.age), 1041 | 0, 2 * pi); 1042 | context.stroke(); 1043 | } 1044 | } 1045 | } 1046 | }, 1047 | 1048 | // Draw the origin nodes 1049 | origins: { 1050 | active: true, 1051 | order: -2, 1052 | draw: function(context) { 1053 | context.globalAlpha = 0.65; 1054 | context.fillStyle = "#fff"; 1055 | 1056 | var cities = linkModels.origins.getCities(); 1057 | 1058 | var ceil = Math.ceil; 1059 | var pi = Math.PI; 1060 | 1061 | for (var i = 0; i < cities.length; i++) { 1062 | var total = linkModels.origins.total(cities[i].counts), 1063 | latlng = projection([cities[i].longitude, 1064 | cities[i].latitude]), 1065 | r = ceil(circleScale(total)); 1066 | context.beginPath(); 1067 | context.arc(latlng[0], latlng[1], r, 0, pi * 2); 1068 | context.fill(); 1069 | } 1070 | } 1071 | }, 1072 | 1073 | // Draw the city nodes 1074 | targets: { 1075 | active: true, 1076 | order: -2, 1077 | draw: function(context) { 1078 | context.globalAlpha = 0.65; 1079 | context.strokeStyle = "#fff"; 1080 | context.fillStyle = "#fff"; 1081 | 1082 | var cities = linkModels.targets.getCities(); 1083 | 1084 | var ceil = Math.ceil; 1085 | var pi = Math.PI; 1086 | 1087 | for (var i = 0; i < cities.length; i++) { 1088 | var total = linkModels.targets.total(cities[i].counts), 1089 | latlng = projection([cities[i].longitude, 1090 | cities[i].latitude]), 1091 | r = ceil(circleScale(total)); 1092 | context.beginPath(); 1093 | context.arc(latlng[0], latlng[1], r, 0, pi * 2); 1094 | context.stroke(); 1095 | context.fillRect(latlng[0] - 1, latlng[1] - 1, 2, 2); 1096 | } 1097 | } 1098 | }, 1099 | 1100 | 1101 | // Draw the target impact 1102 | targetImpact: { 1103 | active: true, 1104 | impactRadiusScale: d3.scale.linear().domain([1, 40]).range([1, 30]), 1105 | impactOpacityScale: d3.scale.linear().domain([1, 40]).range([1, 0]), 1106 | impactWidth: 1, 1107 | 1108 | draw: function(ctx) { 1109 | var pi = Math.PI; 1110 | 1111 | ctx.fillStyle = "#f00"; 1112 | nodeModel.get(nodeModel.TARGETS) 1113 | .forEach(function(n) { 1114 | var c = d3.rgb(colorizer(n.service)), 1115 | afterArrival = n.age - n["arrivalAge"]; 1116 | r = 10; 1117 | 1118 | if ("arrivalAge" in n) { 1119 | var r = this.impactRadiusScale(afterArrival); 1120 | ctx.save(); 1121 | ctx.globalAlpha = this.impactOpacityScale(afterArrival); 1122 | ctx.strokeStyle = c.toString(); 1123 | ctx.lineWidth = this.impactWidth; 1124 | ctx.beginPath(); 1125 | ctx.arc(n.x, n.y, r, 0, 2 * pi); 1126 | ctx.closePath(); 1127 | ctx.stroke(); 1128 | ctx.restore(); 1129 | } 1130 | 1131 | if (n.path.length > 0) { 1132 | var point = n.path[n.path.length - 1]; 1133 | if (n.x != point.x && n.y != point.y) { 1134 | ctx.save(); 1135 | var grd = ctx.createLinearGradient( 1136 | n.x, n.y, point.x, point.y); 1137 | grd.addColorStop(0, rgbaString(c, 1)); 1138 | grd.addColorStop(1, rgbaString(c, 0)); 1139 | ctx.lineCap = 'round'; 1140 | ctx.lineWidth = 2; 1141 | ctx.beginPath(); 1142 | ctx.moveTo(n.x, n.y); 1143 | ctx.strokeStyle = grd; 1144 | ctx.lineTo(point.x, point.y); 1145 | ctx.closePath(); 1146 | ctx.stroke(); 1147 | ctx.restore(); 1148 | } 1149 | } 1150 | 1151 | ctx.drawImage(particler(c.r, c.g, c.b, 1), 1152 | n.x - r / 2, n.y - r / 2, r, r); 1153 | 1154 | }, this); 1155 | } 1156 | }, 1157 | 1158 | // Draw the provided links 1159 | // A link: {source: _, target: _, color: _, width: _} 1160 | // source/target: {x: _, y: _, strokeStyle: _, fillStyle: _} 1161 | links: { 1162 | active: true, 1163 | order: -1, 1164 | data: [], 1165 | 1166 | draw: function(context) { 1167 | var pi = Math.PI; 1168 | 1169 | for (var i = 0; i < this.data.length; i++) { 1170 | context.beginPath(); 1171 | context.strokeStyle = this.data[i].color; 1172 | context.moveTo(this.data[i].source.x, this.data[i].source.y); 1173 | context.lineTo(this.data[i].target.x, this.data[i].target.y); 1174 | context.lineWidth = this.data[i].width; 1175 | context.lineCap = "round"; 1176 | context.stroke(); 1177 | 1178 | context.lineWidth = 2; 1179 | context.beginPath(); 1180 | context.arc(this.data[i].source.x, this.data[i].source.y, 1181 | this.data[i].source.r || 5, 0, pi * 2); 1182 | if (this.data[i].source.fillStyle) { 1183 | context.fillStyle = this.data[i].source.fillStyle; 1184 | context.fill(); 1185 | } 1186 | if (this.data[i].source.strokeStyle) { 1187 | context.strokeStyle = this.data[i].source.strokeStyle; 1188 | context.stroke(); 1189 | } 1190 | 1191 | context.beginPath(); 1192 | context.fillStyle = this.data[i].target.fillStyle || "#fff"; 1193 | context.arc(this.data[i].target.x, this.data[i].target.y, 1194 | this.data[i].target.r || 5, 0, pi * 2); 1195 | if (this.data[i].target.fillStyle) { 1196 | context.fillStyle = this.data[i].target.fillStyle; 1197 | context.fill(); 1198 | } 1199 | if (this.data[i].target.strokeStyle) { 1200 | context.strokeStyle = this.data[i].target.strokeStyle; 1201 | context.stroke(); 1202 | } 1203 | } 1204 | } 1205 | } 1206 | 1207 | }, 1208 | 1209 | // State 1210 | _activeCanvas: { 1211 | canvas: canvas, 1212 | context: canvas.node().getContext("2d") 1213 | }, 1214 | 1215 | _clearContext: function(context) { 1216 | context.save(); 1217 | context.clearRect(0, 0, width, height) 1218 | context.restore(); 1219 | }, 1220 | 1221 | _drawSort: function (d1, d2) { return d1.order || 0 - d2.order || 0; }, 1222 | 1223 | redraw: function() { 1224 | this.drawStart = new Date().getTime(); 1225 | 1226 | // Draw the active drawings 1227 | this._clearContext(this._activeCanvas.context); 1228 | 1229 | for (var drawing in this.drawings) { 1230 | if (this.drawings[drawing].active) { 1231 | this.drawings[drawing].draw(this._activeCanvas.context); 1232 | } 1233 | } 1234 | 1235 | var that = this; 1236 | 1237 | var nextFrame = 1000 / 30 - (new Date().getTime() - this.drawStart); 1238 | 1239 | if (nextFrame < 0) nextFrame = 0; 1240 | 1241 | this._timeout = setTimeout(function() { that.redraw() }, nextFrame); 1242 | }, 1243 | 1244 | start: function(interval) { 1245 | this.redraw(); 1246 | }, 1247 | 1248 | stop: function() { 1249 | clearTimeout(this._timeout); 1250 | } 1251 | } 1252 | 1253 | // Event handling for setting the painter's links 1254 | var _ = (function() { 1255 | var previous; 1256 | function cityKey(n) { 1257 | return [n.country, n.city]; 1258 | } 1259 | 1260 | canvas.on("mousemove", function() { 1261 | // TODO -- this is a hacky mess 1262 | var nearestOrigin = linkModels.origins.pixelsFromNearest(d3.mouse(this)), 1263 | nearestTarget = linkModels.targets.pixelsFromNearest(d3.mouse(this)), 1264 | nearest, msg, model, mapfn, strokeOrigin, strokeTarget; 1265 | if (nearestOrigin || nearestTarget) { 1266 | if (!nearestTarget || nearestOrigin.distance <= nearestTarget.distance) { 1267 | nearest = nearestOrigin; 1268 | msg = "Attacks originating from: "; 1269 | model = linkModels.origins; 1270 | strokeOrigin = true; 1271 | } 1272 | if (!nearestOrigin || nearestTarget.distance < nearestOrigin.distance) { 1273 | nearest = nearestTarget; 1274 | msg = "Attacks targeting: "; 1275 | model = linkModels.targets; 1276 | strokeTarget = true; 1277 | } 1278 | } 1279 | 1280 | if (nearest && nearest.distance < 20) { 1281 | var key = cityKey(nearest); 1282 | if (key !== previous) { 1283 | painter.drawings.links.data = 1284 | model.cityToLinks(nearest, strokeOrigin, strokeTarget); 1285 | displayLabel.set(msg + 1286 | (nearest.city === "" ? "" : nearest.city) 1287 | + ", " + countryModel.getByIso2(nearest.country).country); 1288 | } 1289 | } else { 1290 | previous = key; 1291 | painter.drawings.links.data.length = 0; 1292 | displayLabel.clear(); 1293 | } 1294 | }); 1295 | })(); 1296 | 1297 | /* 1298 | * The legend 1299 | */ 1300 | 1301 | var _ = (function() { 1302 | var attack = d3.select("#particle-legend-content"), 1303 | width = 20, height = 20; 1304 | 1305 | attack.append("canvas") 1306 | .attr("width", width * 1) 1307 | .attr("height", height * 1) 1308 | .node().getContext("2d") 1309 | .drawImage(particler(255, 255, 255, 1), 1310 | width / 8, height / 8, width, height); 1311 | /*var legend = d3.select("#legend-container") 1312 | .append("div") 1313 | .attr("id", "legend"); 1314 | 1315 | var attack = legend.append("div"), 1316 | width = 20, height = 20; 1317 | attack.append("h4").text("Each particle represents an attack."); 1318 | attack.append("canvas") 1319 | .attr("width", width * 2) 1320 | .attr("height", height * 2) 1321 | .node().getContext("2d") 1322 | .drawImage(particler(255, 255, 255, 1), 1323 | width / 2, height / 2, width, height); 1324 | 1325 | var clusters = legend.append("div").attr("class", "clusters"); 1326 | clusters.append("h4").text("Attack origins are grouped into clusters."); 1327 | 1328 | var height = 30; 1329 | var clusterList = clusters.append("ul").selectAll("li") 1330 | .data([1, 10, 200]) 1331 | .enter().append("li"); 1332 | clusterList.append("svg") 1333 | .style("width", function(d) { return circleScale(d) * 2; }) 1334 | .style("height", height) 1335 | .append("circle") 1336 | .attr("fill", "white") 1337 | .attr("cy", function(d) { return height - circleScale(d); }) 1338 | .attr("cx", function(d) { return circleScale(d); }) 1339 | .attr("r", function(d) { return circleScale(d); }); 1340 | clusterList.append("p") 1341 | .text(function(d) { return d; }); 1342 | 1343 | var countryColors = legend.append("div").attr("class", "country-colors"); 1344 | countryColors.append("h4").text("Countries are shaded in as they're attacked."); 1345 | 1346 | var r = 4; 1347 | var countryColorList = countryColors.append("ul").selectAll("li") 1348 | .data([1, 5, 25, 100, 500]) 1349 | .enter().append("li"); 1350 | countryColorList.append("svg") 1351 | .style("width", r * 2) 1352 | .style("height", r * 2) 1353 | .append("circle") 1354 | .attr("fill", function(d) { return settings.countryColor(d); }) 1355 | .attr("cy", r) 1356 | .attr("cx", r) 1357 | .attr("r", r); 1358 | countryColorList.append("p") 1359 | .text(function(d) { return d; });*/ 1360 | })(); 1361 | 1362 | /* 1363 | * Stats the state machine 1364 | */ 1365 | function Stats(params) { 1366 | this.state = params.state || d3.map(); 1367 | this.elt = params.elt || d3.select("body"); 1368 | this.tag = params.tag || "div"; 1369 | 1370 | this.insert = function(incoming) { 1371 | // Insert a new item, updating the state. params.insert should mutate 1372 | params.insert(incoming, this.state); 1373 | }; 1374 | 1375 | this.data = function() { 1376 | // Get the data as a list 1377 | if (params.data) return params.data(this.state); else this.state; 1378 | } 1379 | 1380 | this.redraw = function() { 1381 | if (params.redraw) { 1382 | params.redraw() 1383 | } else { 1384 | this.elt.selectAll(this.tag) 1385 | .data(this.data()) 1386 | .enter().append(this.tag) 1387 | .text(function(d) { return d}); 1388 | } 1389 | } 1390 | } 1391 | 1392 | 1393 | var statsManager = { 1394 | insert: function(incoming) { 1395 | for (var i = 0; i < this.stats.length; ++i) { 1396 | this.stats[i].insert(incoming); 1397 | } 1398 | }, 1399 | 1400 | redraw: function() { 1401 | for (var i = 0; i < this.stats.length; i++) { 1402 | this.stats[i].redraw(); 1403 | } 1404 | }, 1405 | 1406 | stats: [ 1407 | new Stats({ 1408 | // Color countries 1409 | state: {sources: {}, targets: {}}, 1410 | 1411 | insert: function(d, state) { 1412 | function pushState(m, key) { 1413 | if (key in m) { 1414 | m[key] = m[key] + 1; 1415 | } else { 1416 | m[key] = 1; 1417 | } 1418 | } 1419 | 1420 | //pushState(state.sources, d.country); 1421 | pushState(state.targets, d.country2); 1422 | 1423 | //d3.select("#" + d.country) 1424 | // .attr("fill", d3.rgb(colorScale(state.sources[d.country]), 0, 0).toString()); 1425 | d3.select("#" + d.country2) 1426 | .attr("fill", settings.countryColor(state.targets[d.country2])); 1427 | }, 1428 | 1429 | redraw: function() {} 1430 | }), 1431 | 1432 | // Origin data table 1433 | new Stats({ 1434 | state: d3.map(), 1435 | 1436 | insert: function(incoming, state) { 1437 | this.updated = incoming.country; 1438 | if (state.has(incoming.country)) { 1439 | state.set(incoming.country, 1440 | state.get(incoming.country) + 1); 1441 | } else { 1442 | state.set(incoming.country, 1); 1443 | } 1444 | }, 1445 | 1446 | redraw: function() { 1447 | var data = this.state.entries() 1448 | .sort(function(d1, d2) { return d2.value - d1.value; }) 1449 | .slice(0, settings.topTableRows), 1450 | updated = this.updated; 1451 | 1452 | var rows = d3.select("#left-data").selectAll("tr.row") 1453 | .data(data, function(d) { return d.key; }); 1454 | rows.enter() 1455 | .append("tr") 1456 | .attr("class", "row") 1457 | .on("mouseenter", function(d) { 1458 | var country = countryModel.getByIso2(d.key); 1459 | displayLabel.set("Attacks originating from: " + 1460 | (country ? country.country : d.key)); 1461 | 1462 | // On mouseenter, use all country data to create links 1463 | painter.drawings.links.data = 1464 | linkModels.origins.getCountry(d.key) 1465 | .reduce(function(acc, city) { 1466 | return acc.concat( 1467 | linkModels.origins.cityToLinks( 1468 | city, true, false)); 1469 | }, []); 1470 | }) 1471 | .on("mouseleave", function() { 1472 | displayLabel.clear(); 1473 | }); 1474 | rows.sort(function(d1, d2) { return d2.value - d1.value; }); 1475 | rows.exit().remove(); 1476 | 1477 | rows.filter(function(d) {return d.key == updated}) 1478 | .style("color", settings.triggerColor) 1479 | .transition() 1480 | .duration(1000) 1481 | .style("color", "white"); 1482 | 1483 | var cols = rows.selectAll("td") 1484 | .data(function(d) { 1485 | var country = countryModel.getByIso2(d.key); 1486 | return [ 1487 | '
', 1489 | spanWrap(d.value, ["numeric"]), 1490 | flagTag(d.key), 1491 | (country ? country.country : d.key)]; }); 1492 | cols.enter().append("td"); 1493 | cols.html(function(d) { return d; }); 1494 | cols.exit().remove(); 1495 | } 1496 | }), 1497 | 1498 | // Targeted data table 1499 | new Stats({ 1500 | state: d3.map(), 1501 | 1502 | insert: function(incoming, state) { 1503 | this.updated = incoming.country2; 1504 | if (state.has(incoming.country2)) { 1505 | state.set(incoming.country2, 1506 | state.get(incoming.country2) + 1); 1507 | } else { 1508 | state.set(incoming.country2, 1); 1509 | } 1510 | }, 1511 | 1512 | redraw: function() { 1513 | var data = this.state.entries() 1514 | .sort(function(d1, d2) { return d2.value - d1.value; }) 1515 | .slice(0, settings.topTableRows), 1516 | updated = this.updated; 1517 | 1518 | var rows = d3.select("#right-data").selectAll("tr.row") 1519 | .data(data, function(d) { return d.key; }); 1520 | rows.enter() 1521 | .append("tr") 1522 | .attr("class", "row") 1523 | .on("mouseenter", function(d) { 1524 | var country = countryModel.getByIso2(d.key); 1525 | displayLabel.set("Attacks targeting: " + 1526 | (country ? country.country : d.key)); 1527 | 1528 | // On mouseenter, use all country data to create links 1529 | painter.drawings.links.data = 1530 | linkModels.targets.getCountry(d.key) 1531 | .reduce(function(acc, city) { 1532 | return acc.concat( 1533 | linkModels.targets.cityToLinks( 1534 | city, false, true)); 1535 | }, []); 1536 | }) 1537 | .on("mouseleave", function() { 1538 | displayLabel.clear(); 1539 | }); 1540 | rows.sort(function(d1, d2) { return d2.value - d1.value; }); 1541 | rows.exit().remove(); 1542 | 1543 | rows.filter(function(d) {return d.key == updated}) 1544 | .style("color", "blue") 1545 | .transition() 1546 | .duration(1000) 1547 | .style("color", "white"); 1548 | 1549 | var cols = rows.selectAll("td") 1550 | .data(function(d) { 1551 | var country = countryModel.getByIso2(d.key); 1552 | return [ 1553 | '
', 1555 | spanWrap(d.value, ["numeric"]), 1556 | flagTag(d.key), 1557 | (country ? country.country : d.key)]; }); 1558 | cols.enter().append("td"); 1559 | cols.html(function(d) { return d; }); 1560 | cols.exit().remove(); 1561 | } 1562 | }), 1563 | 1564 | new Stats( 1565 | {state: d3.map(), 1566 | 1567 | insert: function(incoming) { 1568 | this.updated = incoming.service; 1569 | if (this.state.has(incoming.service)) { 1570 | this.state.set(incoming.service, 1571 | this.state.get(incoming.service) + 1); 1572 | } else { 1573 | this.state.set(incoming.service, 1); 1574 | } 1575 | }, 1576 | 1577 | redraw: function() { 1578 | var data = this.state.entries() 1579 | .sort(function(d1, d2) { return d2.value - d1.value; }) 1580 | .slice(0, settings.portTableRows), 1581 | updated = this.updated; 1582 | 1583 | var rows = d3.select("#bottom-right-data").selectAll("tr.row") 1584 | // XXX - I'm not sure why d is undef the first time through. 1585 | .data(data, function(d, i) { return d ? d.key : i; }); 1586 | rows.enter() 1587 | .append("tr") 1588 | .attr("class", "row") 1589 | .on("mouseenter", function(d) { 1590 | displayLabel.set("Attacks made over: " + 1591 | (d.service ? d.service : "unknown") + 1592 | " [" + d.key + "]"); 1593 | painter.drawings.links.data = 1594 | linkModels.origins.dPortLinks(d.key).map(function(c) { 1595 | var r = circleScale(c.count), 1596 | color = colorizer(c.service); 1597 | return { 1598 | source: { 1599 | x: c.source.pt[0], 1600 | y: c.source.pt[1], 1601 | fillStyle: color, 1602 | r: r 1603 | }, 1604 | target: { 1605 | x: c.target.pt[0], 1606 | y: c.target.pt[1], 1607 | strokeStyle: color, 1608 | r: r 1609 | }, 1610 | width: lineScale(c.count), 1611 | color: colorizer(c.service) 1612 | } 1613 | }); 1614 | }) 1615 | .on("mouseleave", function(d) { 1616 | displayLabel.clear(); 1617 | }) 1618 | rows.sort(function(d1, d2) { return d2.value - d1.value; }); 1619 | rows.exit().remove(); 1620 | 1621 | rows.filter(function(d) {return d.key == updated}) 1622 | .style("color", function(d) { return colorizer(d.key); }) 1623 | .transition() 1624 | .duration(1000) 1625 | .style("color", "white"); 1626 | 1627 | var cols = rows.selectAll("td") 1628 | .data(function(d) { 1629 | return [ 1630 | '
', 1632 | spanWrap(d.value, ["numeric"]), 1633 | '', 1635 | d.key 1636 | ]; }); 1637 | //function(d) { return d; }); 1638 | cols.enter().append("td"); 1639 | cols.html(function(d) { return d; }); 1640 | cols.exit().remove(); 1641 | } 1642 | }), 1643 | 1644 | new Stats({ 1645 | // #console stats manager 1646 | state: [], 1647 | 1648 | insert: function(incoming, state) { 1649 | state.push(incoming); 1650 | while (state.length > settings.consoleTableRows) { 1651 | state.shift(); 1652 | } 1653 | return state; 1654 | }, 1655 | 1656 | redraw: function() { 1657 | var that = this; 1658 | var rows = d3.select("#events-data").selectAll("tr.row") 1659 | .data(this.state, function(d) { return d.id; }); 1660 | 1661 | rows.enter().append("tr") 1662 | .style("color", function(d) { return colorizer(d.service); }) 1663 | .attr("class", "row"); 1664 | rows.exit().remove(); 1665 | 1666 | var cols = rows.selectAll("td") 1667 | .data(function(d) { 1668 | return [ 1669 | d.datetime, 1670 | spanWrap( 1671 | (d.city === "" ? "unknown" : d.city) + ", " + 1672 | countryModel.getByIso2(d.country).country, 1673 | ["location", "overflow"]), 1674 | d.md5, 1675 | d.hostip, 1676 | spanWrap( 1677 | (d.city2 === "" ? "unknown" : d.city2) + ", " + 1678 | countryModel.getByIso2(d.country2).country, 1679 | ["location", "overflow", "numeric"]), 1680 | d.service]; }); 1681 | cols.enter().append("td") 1682 | .html(function(d) { return d; }); 1683 | cols.exit().remove(); 1684 | } 1685 | 1686 | }) 1687 | ]}; 1688 | 1689 | // Keep track of the rate 1690 | var rateTicker = { 1691 | data: [], 1692 | interval: 90000, 1693 | graph: d3.select("#content") 1694 | .append("svg") 1695 | .attr("id", "rate-graph"), 1696 | x: d3.time.scale().range([800, 0]), 1697 | opacity: d3.time.scale().range([0, 1]), 1698 | 1699 | push: function(d) { 1700 | this.data.push({date: Date.now(), key: d.service}); 1701 | }, 1702 | 1703 | clean: function(toDate) { 1704 | // Clean out old data 1705 | while (this.data.length > 0 && this.data[0].date < toDate) { 1706 | this.data.shift(); 1707 | } 1708 | }, 1709 | 1710 | step: function() { 1711 | var that = this, 1712 | now = Date.now(), 1713 | range = [now - this.interval, now]; 1714 | this.clean(range[0]); 1715 | this.x.domain(range); 1716 | this.opacity.domain(range); 1717 | 1718 | var simpleLine = function(h) { 1719 | return function(d) { 1720 | var cx = that.x(d.date); 1721 | return d3.svg.line()([[cx, 0], [cx, h || 20]])}}; 1722 | var ticks = this.graph.selectAll("path.tick") 1723 | .data(this.data, function(d) { return d.date; }); 1724 | 1725 | ticks.enter().append("path") 1726 | .attr("class", "tick") 1727 | .attr("d", simpleLine()) 1728 | .style("stroke", function(d) { return colorizer(d.key); }); 1729 | 1730 | ticks.exit().remove(); 1731 | 1732 | ticks 1733 | //.transition().duration(30) 1734 | .attr("d", simpleLine()) 1735 | .style("opacity", function(d) { return that.opacity(d.date); }); 1736 | }, 1737 | 1738 | start: function() { 1739 | var that = this; 1740 | setInterval(function() { that.step(); }, 50); 1741 | } 1742 | }; 1743 | 1744 | 1745 | var wsDiscTime = 0; 1746 | 1747 | function start(loc, psk) { 1748 | var webSocket = new WebSocket(loc || settings.wsHost); 1749 | 1750 | var pauser = { 1751 | elt: d3.selectAll(".controls"), 1752 | _buffer: [], 1753 | 1754 | unbuffer: function(d) { 1755 | while (this._buffer.length > 0) { 1756 | this.insert(this._buffer.shift()); 1757 | } 1758 | statsManager.redraw(); 1759 | }, 1760 | 1761 | insert: function(d) { 1762 | nodeModel.pushAttack(d); 1763 | statsManager.insert(d); 1764 | for (var model in linkModels) { 1765 | linkModels[model].insert(d); 1766 | } 1767 | rateTicker.push(d); 1768 | 1769 | d.pruneTS = new Date().getTime() / 1000 + settings.pruneInterval; 1770 | timestampedData.push(d); 1771 | }, 1772 | 1773 | push: function(d) { 1774 | if (this.paused()) { 1775 | this._buffer.push(d); 1776 | } else { 1777 | this.insert(d); 1778 | statsManager.redraw(); 1779 | } 1780 | }, 1781 | 1782 | paused: function() { 1783 | return this.elt.node().dataset.paused === "true"; 1784 | }, 1785 | 1786 | toggle: function() { 1787 | var dataset = this.elt.node().dataset; 1788 | var button = d3.selectAll(".play-pause"); 1789 | 1790 | if (this.paused()) { 1791 | button.classed("icon-play", false); 1792 | button.classed("icon-pause", true); 1793 | this.elt.node().dataset.paused = "false"; 1794 | this.unbuffer(); 1795 | } else { 1796 | button.classed("icon-pause", false); 1797 | button.classed("icon-play", true); 1798 | this.elt.node().dataset.paused = "true"; 1799 | } 1800 | } 1801 | } 1802 | pauser.elt.on("click", function() { pauser.toggle(); }); 1803 | 1804 | webSocket.onopen = function() { 1805 | wsDiscTime = 0; 1806 | d3.select("#events-data").selectAll("tr.row").remove(); 1807 | webSocket.send(psk || settings.psk); 1808 | }; 1809 | 1810 | webSocket.onmessage = function(evt) { 1811 | if (!evt) { 1812 | return; 1813 | } 1814 | 1815 | 1816 | // Parse the json to a js obj and clean the data 1817 | var datum = eval("(" + evt.data + ")"); 1818 | 1819 | if (datum.longitude == 0 && datum.latitude == 0) { 1820 | datum.longitude = -5; 1821 | datum.latitude = -50; 1822 | } 1823 | 1824 | var startLoc = projection([datum.longitude, datum.latitude]); 1825 | var endLoc = projection([datum.longitude2, datum.latitude2]); 1826 | 1827 | if (datum.error) { 1828 | showMessage("ERROR: " + datum.error.msg); 1829 | } 1830 | 1831 | for (var prop in datum) { 1832 | if (settings.numberProps.indexOf(prop) !== -1) { 1833 | datum[prop] = Number(datum[prop]); 1834 | } 1835 | } 1836 | 1837 | function cleanCountry(country) { 1838 | // Clean incoming country code 1839 | if (country === "USA") { 1840 | return "US"; 1841 | } 1842 | return country 1843 | } 1844 | 1845 | datum.country = cleanCountry(datum.country); 1846 | datum.country2 = cleanCountry(datum.country2); 1847 | 1848 | datum.service = datum.type; 1849 | datum.cx = startLoc[0]; 1850 | datum.cy = startLoc[1]; 1851 | datum.x = startLoc[0]; 1852 | datum.y = startLoc[1]; 1853 | datum.targetX = endLoc[0]; 1854 | datum.targetY = endLoc[1]; 1855 | datum.id = getID(); 1856 | datum.datetime = (new Date()).toISOString() 1857 | .replace("T", " ") 1858 | .slice(0, -2); 1859 | 1860 | console.log(datum); 1861 | pauser.push(datum); 1862 | }; 1863 | 1864 | webSocket.onclose = function() { 1865 | //try to reconnect in 5 seconds 1866 | var interval = 500; 1867 | 1868 | wsDiscTime += 500; 1869 | 1870 | d3.select("#events-data").selectAll("tr.row").remove(); 1871 | d3.select("#events-data").append("tr").attr('class', 'row').html(" Loading..."); 1872 | 1873 | if (wsDiscTime > settings.wsTimeout) { 1874 | showMessage("We are having difficulties in the WebSocket connectivity. We will continue trying..."); 1875 | wsDiscTime = 0; 1876 | } 1877 | 1878 | setTimeout(function(){ 1879 | console.log("websocket closed, reconnecting in " + interval + "ms"); 1880 | start(loc, psk); 1881 | }, interval); 1882 | }; 1883 | 1884 | return webSocket; 1885 | } 1886 | 1887 | /* 1888 | * Load external data, and manage loading state 1889 | */ 1890 | 1891 | queue() 1892 | .defer(d3.json, "data/readme-world.json") 1893 | .defer(d3.csv, "data/country-codes.csv") 1894 | .await(function (error, world, rawPorts, countryCodes) { 1895 | // Update the countryModel 1896 | countryModel.set(countryCodes); 1897 | countryModel.push({iso2: "O1", country: "Mil/Gov"}); 1898 | 1899 | // Temporary mapping to key the map 1900 | var mapCodes = {}; 1901 | countryCodes.forEach(function(d) { mapCodes[Number(d.isonum)] = d.iso2; }); 1902 | 1903 | // Enter the countries 1904 | svg.append("g") 1905 | .attr("class", "world") 1906 | .selectAll("path") 1907 | .data(topojson.feature(world, world.objects.countries).features) 1908 | .enter().insert("path") 1909 | .attr("class", "country") 1910 | .attr("id", function(d) { return mapCodes[d.id]; }) 1911 | .attr("fill", settings.countryColor(0)) 1912 | .attr("d", path); 1913 | 1914 | ports = parsePorts(rawPorts); 1915 | 1916 | loadingToggle(); 1917 | var webSocket = start(); 1918 | nodeModel.start(); 1919 | painter.start(); 1920 | rateTicker.start(); 1921 | }); 1922 | 1923 | // Export the external API 1924 | window.IPViking = { 1925 | settings: settings 1926 | } 1927 | 1928 | var unknownLoc = projection([-5, -50]); 1929 | 1930 | d3.selectAll("#unknown-icon").style({'left': unknownLoc[0] - 18, 'top': unknownLoc[1] - 18}); 1931 | 1932 | setInterval(function () { prune(); }, 30000); 1933 | })(window); 1934 | -------------------------------------------------------------------------------- /nodejs/main.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | var ws = require("nodejs-websocket") 3 | var sleep = require('sleep'); 4 | var geoip = require('geoip-lite'); 5 | var _ = require('underscore'); 6 | var mysql = require('mysql'); 7 | var connection = mysql.createConnection({ 8 | host : '127.0.0.1', 9 | user : 'your_user', 10 | password : 'your_password', 11 | port : 3306, 12 | database : 'your_database' 13 | }); 14 | var id=0; 15 | 16 | //连接mysql 17 | connection.connect(); 18 | 19 | //创建服务器 20 | var server = ws.createServer(function (conn) { 21 | console.log("New connection") 22 | conn.on("text", function (str) { 23 | console.log("Received "+str) 24 | }) 25 | conn.on("close", function (code, reason) { 26 | console.log("Connection closed") 27 | }) 28 | }).listen(8085) 29 | 30 | //发送实时消息 31 | setInterval(function () { 32 | try { 33 | sql = 'SELECT * from td_protectclient_attack_log2 where id>'+id+' and attacktype!=\'360webscan scan\''; 34 | if(id==0) 35 | sql = sql+' order by id desc limit 100'; 36 | else 37 | sql = sql+'limit 10'; 38 | connection.query(sql, function(err, rows, fields) { 39 | if (err) throw err; 40 | _.each(rows, function(a) { 41 | //console.log(a); 42 | id = Math.max(id, a.id); 43 | var attack_ll = geoip.lookup(a.clientip); 44 | var host_ll = geoip.lookup(a.ipstr); 45 | //console.log(host_ll); 46 | server.connections.forEach(function (conn) { 47 | if (attack_ll && attack_ll.ll && host_ll && host_ll.ll) 48 | conn.sendText('{"latitude":"'+attack_ll.ll[0]+'","longitude":"'+attack_ll.ll[1]+'","countrycode":"'+attack_ll.country+'","country":"'+attack_ll.country+'","city":"'+attack_ll.city+'","latitude2":"'+host_ll.ll[0]+'","longitude2":"'+host_ll.ll[1]+'","countrycode2":"'+host_ll.country+'","country2":"'+host_ll.country+'","city2":"'+host_ll.city+'","type":"'+a.attacktype+'","md5":"'+a.clientip+'","hostip":"'+a.ipstr+'"}'); 49 | }); 50 | }); 51 | }); 52 | } catch (e) { 53 | console.log('Error!'); 54 | console.log(e); 55 | } 56 | }, 1000); 57 | -------------------------------------------------------------------------------- /presentations.js: -------------------------------------------------------------------------------- 1 | ;"use strict"; 2 | (function(IPViking) { 3 | // Toggle table size settings 4 | state = false; 5 | states = [{topTableRows: 16, portTableRows: 15, consoleTableRows: 16}, 6 | {topTableRows: 10, portTableRows: 8, consoleTableRows: 8}]; 7 | d3.select("body").on("keydown", function() { 8 | d3.event.preventDefault; 9 | if (d3.event.keyCode == 83) { 10 | for (var setting in states[state + 0]) { 11 | IPViking.settings[setting] = states[state + 0][setting]; 12 | } 13 | state = !state; 14 | } 15 | }); 16 | })(window.IPViking); 17 | --------------------------------------------------------------------------------