-
36 |
- Add/remove connections by clicking them. 37 |
- Shift-click to send packets to a specific node. 38 |
├── js ├── README.md ├── helpers.js ├── lib │ ├── pubsub.js │ ├── info.js │ ├── sketch.js │ └── Markdown.Converter.js ├── settings.js ├── stats.hbs ├── edge.js ├── packets.js ├── main.js ├── node.js ├── packet.js ├── network.js └── stats.js ├── .gitignore ├── .eslintignore ├── img └── img.png ├── todo.md ├── css ├── reset.css ├── style.css └── info.css ├── package.json ├── .eslintrc ├── index.html └── README.md /js/README.md: -------------------------------------------------------------------------------- 1 | ./README.md -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | build 2 | js/lib 3 | node_modules 4 | -------------------------------------------------------------------------------- /img/img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cafe/rota/master/img/img.png -------------------------------------------------------------------------------- /js/helpers.js: -------------------------------------------------------------------------------- 1 | var Sketch = require('./lib/sketch'); 2 | let helpers = {}; 3 | Sketch.install(helpers); 4 | module.exports = helpers; 5 | -------------------------------------------------------------------------------- /js/lib/pubsub.js: -------------------------------------------------------------------------------- 1 | var Backbone = require('backbone'); 2 | var _ = require('underscore'); 3 | 4 | var Pubsub = _.clone(Backbone.Events); 5 | window.Pubsub = Pubsub; 6 | 7 | modules.exports = Pubsub; 8 | -------------------------------------------------------------------------------- /js/settings.js: -------------------------------------------------------------------------------- 1 | const SPACING = 50; 2 | const SPEED = 1; 3 | const LATENCY_RANGE = [20, 180].map((num) => num * SPEED); 4 | const REDZONE_TIME = 40 * (LATENCY_RANGE[0] + LATENCY_RANGE[1]) / 2; 5 | const ROW_COLUMN_COUNT = 7; 6 | 7 | const settings = { 8 | LATENCY_RANGE, 9 | REDZONE_TIME, 10 | SPACING, 11 | ROW_COLUMN_COUNT 12 | }; 13 | 14 | module.exports = settings; 15 | -------------------------------------------------------------------------------- /todo.md: -------------------------------------------------------------------------------- 1 | # To Do 2 | 3 | - Show heatmaps by clicking on each node (Or draw paths for best paths) 4 | - How do we show directionality of paths? 5 | - packet TTLs 6 | 7 | - adjust render speed 8 | 9 | - allow edges to change in latency (based on usage)? 10 | 11 | - show chart with sliding window instead of packet delivery averages 12 | - use dat.gui and have controls for settings constants 13 | - include progress bar to show how fully "trained" the grid is - maybe each node needs to have a certain number of iterations per address? This way it's easy to indicate that the grid has been reset? 14 | -------------------------------------------------------------------------------- /css/reset.css: -------------------------------------------------------------------------------- 1 | /* Eric Meyer's Reset CSS v2.0 - http://cssreset.com */ 2 | html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0} 3 | -------------------------------------------------------------------------------- /js/stats.hbs: -------------------------------------------------------------------------------- 1 |
| {{total}} | 4 |Total | 5 |
| {{inFlight}} | 8 |In-Flight | 9 |
| {{delivered}} | 12 |Delivered | 13 |
| {{averageTime}} | 16 |Average Time (ms) | 17 |
| Send Rate (per second) | 20 |{{rate}} | 21 |
| Total Paths | 26 |{{pathCount}} | 27 |
| Average Runs/Path | 30 |{{averagePathCount}} | 31 |
| Average Best | 34 |{{averageBest}} | 35 |
| Average Best/Actual Ratio | 38 |1 : {{averageBestActualRatio}} | 39 |
s around 271 | // "paragraphs" that are wrapped in non-block-level tags, such as anchors, 272 | // phrase emphasis, and spans. The list of tags we're looking for is 273 | // hard-coded: 274 | var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del" 275 | var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math" 276 | 277 | // First, look for nested blocks, e.g.: 278 | //
tags around block-level tags.
430 | text = _HashHTMLBlocks(text);
431 | text = _FormParagraphs(text, doNotUnhash);
432 |
433 | return text;
434 | }
435 |
436 | function _RunSpanGamut(text) {
437 | //
438 | // These are all the transformations that occur *within* block-level
439 | // tags like paragraphs, headers, and list items.
440 | //
441 |
442 | text = pluginHooks.preSpanGamut(text);
443 |
444 | text = _DoCodeSpans(text);
445 | text = _EscapeSpecialCharsWithinTagAttributes(text);
446 | text = _EncodeBackslashEscapes(text);
447 |
448 | // Process anchor and image tags. Images must come first,
449 | // because ![foo][f] looks like an anchor.
450 | text = _DoImages(text);
451 | text = _DoAnchors(text);
452 |
453 | // Make links out of things like ` Just type tags
1146 | //
1147 |
1148 | // Strip leading and trailing lines:
1149 | text = text.replace(/^\n+/g, "");
1150 | text = text.replace(/\n+$/g, "");
1151 |
1152 | var grafs = text.split(/\n{2,}/g);
1153 | var grafsOut = [];
1154 |
1155 | var markerRe = /~K(\d+)K/;
1156 |
1157 | //
1158 | // Wrap tags.
1159 | //
1160 | var end = grafs.length;
1161 | for (var i = 0; i < end; i++) {
1162 | var str = grafs[i];
1163 |
1164 | // if this is an HTML marker, copy it
1165 | if (markerRe.test(str)) {
1166 | grafsOut.push(str);
1167 | }
1168 | else if (/\S/.test(str)) {
1169 | str = _RunSpanGamut(str);
1170 | str = str.replace(/^([ \t]*)/g, " ");
1171 | str += "
\n");
465 |
466 | text = pluginHooks.postSpanGamut(text);
467 |
468 | return text;
469 | }
470 |
471 | function _EscapeSpecialCharsWithinTagAttributes(text) {
472 | //
473 | // Within tags -- meaning between < and > -- encode [\ ` * _] so they
474 | // don't conflict with their use in Markdown for code, italics and strong.
475 | //
476 |
477 | // Build a regex to find HTML tags and comments. See Friedl's
478 | // "Mastering Regular Expressions", 2nd Ed., pp. 200-201.
479 |
480 | // SE: changed the comment part of the regex
481 |
482 | var regex = /(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|-]|-[^>])(?:[^-]|-[^-])*)--)>)/gi;
483 |
484 | text = text.replace(regex, function (wholeMatch) {
485 | var tag = wholeMatch.replace(/(.)<\/?code>(?=.)/g, "$1`");
486 | tag = escapeCharacters(tag, wholeMatch.charAt(1) == "!" ? "\\`*_/" : "\\`*_"); // also escape slashes in comments to prevent autolinking there -- http://meta.stackoverflow.com/questions/95987
487 | return tag;
488 | });
489 |
490 | return text;
491 | }
492 |
493 | function _DoAnchors(text) {
494 | //
495 | // Turn Markdown link shortcuts into XHTML tags.
496 | //
497 | //
498 | // First, handle reference-style links: [link text] [id]
499 | //
500 |
501 | /*
502 | text = text.replace(/
503 | ( // wrap whole match in $1
504 | \[
505 | (
506 | (?:
507 | \[[^\]]*\] // allow brackets nested one level
508 | |
509 | [^\[] // or anything else
510 | )*
511 | )
512 | \]
513 |
514 | [ ]? // one optional space
515 | (?:\n[ ]*)? // one optional newline followed by spaces
516 |
517 | \[
518 | (.*?) // id = $3
519 | \]
520 | )
521 | ()()()() // pad remaining backreferences
522 | /g, writeAnchorTag);
523 | */
524 | text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeAnchorTag);
525 |
526 | //
527 | // Next, inline-style links: [link text](url "optional title")
528 | //
529 |
530 | /*
531 | text = text.replace(/
532 | ( // wrap whole match in $1
533 | \[
534 | (
535 | (?:
536 | \[[^\]]*\] // allow brackets nested one level
537 | |
538 | [^\[\]] // or anything else
539 | )*
540 | )
541 | \]
542 | \( // literal paren
543 | [ \t]*
544 | () // no id, so leave $3 empty
545 | ( // href = $4
546 | (?:
547 | \([^)]*\) // allow one level of (correctly nested) parens (think MSDN)
548 | |
549 | [^()\s]
550 | )*?
551 | )>?
552 | [ \t]*
553 | ( // $5
554 | (['"]) // quote char = $6
555 | (.*?) // Title = $7
556 | \6 // matching quote
557 | [ \t]* // ignore any spaces/tabs between closing quote and )
558 | )? // title is optional
559 | \)
560 | )
561 | /g, writeAnchorTag);
562 | */
563 |
564 | text = text.replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()((?:\([^)]*\)|[^()\s])*?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeAnchorTag);
565 |
566 | //
567 | // Last, handle reference-style shortcuts: [link text]
568 | // These must come last in case you've also got [link test][1]
569 | // or [link test](/foo)
570 | //
571 |
572 | /*
573 | text = text.replace(/
574 | ( // wrap whole match in $1
575 | \[
576 | ([^\[\]]+) // link text = $2; can't contain '[' or ']'
577 | \]
578 | )
579 | ()()()()() // pad rest of backreferences
580 | /g, writeAnchorTag);
581 | */
582 | text = text.replace(/(\[([^\[\]]+)\])()()()()()/g, writeAnchorTag);
583 |
584 | return text;
585 | }
586 |
587 | function writeAnchorTag(wholeMatch, m1, m2, m3, m4, m5, m6, m7) {
588 | if (m7 == undefined) m7 = "";
589 | var whole_match = m1;
590 | var link_text = m2.replace(/:\/\//g, "~P"); // to prevent auto-linking withing the link. will be converted back after the auto-linker runs
591 | var link_id = m3.toLowerCase();
592 | var url = m4;
593 | var title = m7;
594 |
595 | if (url == "") {
596 | if (link_id == "") {
597 | // lower-case and turn embedded newlines into spaces
598 | link_id = link_text.toLowerCase().replace(/ ?\n/g, " ");
599 | }
600 | url = "#" + link_id;
601 |
602 | if (g_urls.get(link_id) != undefined) {
603 | url = g_urls.get(link_id);
604 | if (g_titles.get(link_id) != undefined) {
605 | title = g_titles.get(link_id);
606 | }
607 | }
608 | else {
609 | if (whole_match.search(/\(\s*\)$/m) > -1) {
610 | // Special case for explicit empty url
611 | url = "";
612 | } else {
613 | return whole_match;
614 | }
615 | }
616 | }
617 | url = encodeProblemUrlChars(url);
618 | url = escapeCharacters(url, "*_");
619 | var result = "" + link_text + "";
628 |
629 | return result;
630 | }
631 |
632 | function _DoImages(text) {
633 | //
634 | // Turn Markdown image shortcuts into tags.
635 | //
636 |
637 | //
638 | // First, handle reference-style labeled images: ![alt text][id]
639 | //
640 |
641 | /*
642 | text = text.replace(/
643 | ( // wrap whole match in $1
644 | !\[
645 | (.*?) // alt text = $2
646 | \]
647 |
648 | [ ]? // one optional space
649 | (?:\n[ ]*)? // one optional newline followed by spaces
650 |
651 | \[
652 | (.*?) // id = $3
653 | \]
654 | )
655 | ()()()() // pad rest of backreferences
656 | /g, writeImageTag);
657 | */
658 | text = text.replace(/(!\[(.*?)\][ ]?(?:\n[ ]*)?\[(.*?)\])()()()()/g, writeImageTag);
659 |
660 | //
661 | // Next, handle inline images: 
662 | // Don't forget: encode * and _
663 |
664 | /*
665 | text = text.replace(/
666 | ( // wrap whole match in $1
667 | !\[
668 | (.*?) // alt text = $2
669 | \]
670 | \s? // One optional whitespace character
671 | \( // literal paren
672 | [ \t]*
673 | () // no id, so leave $3 empty
674 | (\S+?)>? // src url = $4
675 | [ \t]*
676 | ( // $5
677 | (['"]) // quote char = $6
678 | (.*?) // title = $7
679 | \6 // matching quote
680 | [ \t]*
681 | )? // title is optional
682 | \)
683 | )
684 | /g, writeImageTag);
685 | */
686 | text = text.replace(/(!\[(.*?)\]\s?\([ \t]*()(\S+?)>?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, writeImageTag);
687 |
688 | return text;
689 | }
690 |
691 | function attributeEncode(text) {
692 | // unconditionally replace angle brackets here -- what ends up in an attribute (e.g. alt or title)
693 | // never makes sense to have verbatim HTML in it (and the sanitizer would totally break it)
694 | return text.replace(/>/g, ">").replace(/";
738 |
739 | return result;
740 | }
741 |
742 | function _DoHeaders(text) {
743 |
744 | // Setext-style headers:
745 | // Header 1
746 | // ========
747 | //
748 | // Header 2
749 | // --------
750 | //
751 | text = text.replace(/^(.+)[ \t]*\n=+[ \t]*\n+/gm,
752 | function (wholeMatch, m1) { return "
" + _RunSpanGamut(m1) + "
\n\n"; }
753 | );
754 |
755 | text = text.replace(/^(.+)[ \t]*\n-+[ \t]*\n+/gm,
756 | function (matchFound, m1) { return "" + _RunSpanGamut(m1) + "
\n\n"; }
757 | );
758 |
759 | // atx-style headers:
760 | // # Header 1
761 | // ## Header 2
762 | // ## Header 2 with closing hashes ##
763 | // ...
764 | // ###### Header 6
765 | //
766 |
767 | /*
768 | text = text.replace(/
769 | ^(\#{1,6}) // $1 = string of #'s
770 | [ \t]*
771 | (.+?) // $2 = Header text
772 | [ \t]*
773 | \#* // optional closing #'s (not counted)
774 | \n+
775 | /gm, function() {...});
776 | */
777 |
778 | text = text.replace(/^(\#{1,6})[ \t]*(.+?)[ \t]*\#*\n+/gm,
779 | function (wholeMatch, m1, m2) {
780 | var h_level = m1.length;
781 | return "` blocks.
954 | //
955 |
956 | /*
957 | text = text.replace(/
958 | (?:\n\n|^)
959 | ( // $1 = the code block -- one or more lines, starting with a space/tab
960 | (?:
961 | (?:[ ]{4}|\t) // Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width
962 | .*\n+
963 | )+
964 | )
965 | (\n*[ ]{0,3}[^ \t\n]|(?=~0)) // attacklab: g_tab_width
966 | /g ,function(){...});
967 | */
968 |
969 | // attacklab: sentinel workarounds for lack of \A and \Z, safari\khtml bug
970 | text += "~0";
971 |
972 | text = text.replace(/(?:\n\n|^\n?)((?:(?:[ ]{4}|\t).*\n+)+)(\n*[ ]{0,3}[^ \t\n]|(?=~0))/g,
973 | function (wholeMatch, m1, m2) {
974 | var codeblock = m1;
975 | var nextChar = m2;
976 |
977 | codeblock = _EncodeCode(_Outdent(codeblock));
978 | codeblock = _Detab(codeblock);
979 | codeblock = codeblock.replace(/^\n+/g, ""); // trim leading newlines
980 | codeblock = codeblock.replace(/\n+$/g, ""); // trim trailing whitespace
981 |
982 | codeblock = "
";
983 |
984 | return "\n\n" + codeblock + "\n\n" + nextChar;
985 | }
986 | );
987 |
988 | // attacklab: strip sentinel
989 | text = text.replace(/~0/, "");
990 |
991 | return text;
992 | }
993 |
994 | function hashBlock(text) {
995 | text = text.replace(/(^\n+|\n+$)/g, "");
996 | return "\n\n~K" + (g_html_blocks.push(text) - 1) + "K\n\n";
997 | }
998 |
999 | function _DoCodeSpans(text) {
1000 | //
1001 | // * Backtick quotes are used for " + codeblock + "\n spans.
1002 | //
1003 | // * You can use multiple backticks as the delimiters if you want to
1004 | // include literal backticks in the code span. So, this input:
1005 | //
1006 | // Just type ``foo `bar` baz`` at the prompt.
1007 | //
1008 | // Will translate to:
1009 | //
1010 | // foo `bar` baz at the prompt.`bar` ...
1023 | //
1024 |
1025 | /*
1026 | text = text.replace(/
1027 | (^|[^\\]) // Character before opening ` can't be a backslash
1028 | (`+) // $2 = Opening run of `
1029 | ( // $3 = The code block
1030 | [^\r]*?
1031 | [^`] // attacklab: work around lack of lookbehind
1032 | )
1033 | \2 // Matching closer
1034 | (?!`)
1035 | /gm, function(){...});
1036 | */
1037 |
1038 | text = text.replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,
1039 | function (wholeMatch, m1, m2, m3, m4) {
1040 | var c = m3;
1041 | c = c.replace(/^([ \t]*)/g, ""); // leading whitespace
1042 | c = c.replace(/[ \t]*$/g, ""); // trailing whitespace
1043 | c = _EncodeCode(c);
1044 | c = c.replace(/:\/\//g, "~P"); // to prevent auto-linking. Not necessary in code *blocks*, but in code spans. Will be converted back after the auto-linker runs.
1045 | return m1 + "" + c + "";
1046 | }
1047 | );
1048 |
1049 | return text;
1050 | }
1051 |
1052 | function _EncodeCode(text) {
1053 | //
1054 | // Encode/escape certain characters inside Markdown code runs.
1055 | // The point is that in code, these characters are literals,
1056 | // and lose their special Markdown meanings.
1057 | //
1058 | // Encode all ampersands; HTML entities are not
1059 | // entities within a Markdown code span.
1060 | text = text.replace(/&/g, "&");
1061 |
1062 | // Do the angle bracket song and dance:
1063 | text = text.replace(//g, ">");
1065 |
1066 | // Now, escape characters that are magic in Markdown:
1067 | text = escapeCharacters(text, "\*_{}[]\\", false);
1068 |
1069 | // jj the line above breaks this:
1070 | //---
1071 |
1072 | //* Item
1073 |
1074 | // 1. Subitem
1075 |
1076 | // special char: *
1077 | //---
1078 |
1079 | return text;
1080 | }
1081 |
1082 | function _DoItalicsAndBold(text) {
1083 |
1084 | // must go first:
1085 | text = text.replace(/([\W_]|^)(\*\*|__)(?=\S)([^\r]*?\S[\*_]*)\2([\W_]|$)/g,
1086 | "$1$3$4");
1087 |
1088 | text = text.replace(/([\W_]|^)(\*|_)(?=\S)([^\r\*_]*?\S)\2([\W_]|$)/g,
1089 | "$1$3$4");
1090 |
1091 | return text;
1092 | }
1093 |
1094 | function _DoBlockQuotes(text) {
1095 |
1096 | /*
1097 | text = text.replace(/
1098 | ( // Wrap whole match in $1
1099 | (
1100 | ^[ \t]*>[ \t]? // '>' at the start of a line
1101 | .+\n // rest of the first line
1102 | (.+\n)* // subsequent consecutive lines
1103 | \n* // blanks
1104 | )+
1105 | )
1106 | /gm, function(){...});
1107 | */
1108 |
1109 | text = text.replace(/((^[ \t]*>[ \t]?.+\n(.+\n)*\n*)+)/gm,
1110 | function (wholeMatch, m1) {
1111 | var bq = m1;
1112 |
1113 | // attacklab: hack around Konqueror 3.5.4 bug:
1114 | // "----------bug".replace(/^-/g,"") == "bug"
1115 |
1116 | bq = bq.replace(/^[ \t]*>[ \t]?/gm, "~0"); // trim one level of quoting
1117 |
1118 | // attacklab: clean up hack
1119 | bq = bq.replace(/~0/g, "");
1120 |
1121 | bq = bq.replace(/^[ \t]+$/gm, ""); // trim whitespace-only lines
1122 | bq = _RunBlockGamut(bq); // recurse
1123 |
1124 | bq = bq.replace(/(^|\n)/g, "$1 ");
1125 | // These leading spaces screw with content, so we need to fix that:
1126 | bq = bq.replace(
1127 | /(\s*
[^\r]+?<\/pre>)/gm,
1128 | function (wholeMatch, m1) {
1129 | var pre = m1;
1130 | // attacklab: hack around Konqueror 3.5.4 bug:
1131 | pre = pre.replace(/^ /mg, "~0");
1132 | pre = pre.replace(/~0/g, "");
1133 | return pre;
1134 | });
1135 |
1136 | return hashBlock("\n" + bq + "\n
");
1137 | }
1138 | );
1139 | return text;
1140 | }
1141 |
1142 | function _FormParagraphs(text, doNotUnhash) {
1143 | //
1144 | // Params:
1145 | // $text - string to process with html