[tor-commits] [sbws/master] fix: docs: Rename section, add diagrams

juga at torproject.org juga at torproject.org
Fri Feb 26 10:18:07 UTC 2021


commit 81fef71ddfb7b34e6a7797b34593cf709e4c6caf
Author: juga0 <juga at riseup.net>
Date:   Thu Feb 18 12:27:29 2021 +0000

    fix: docs: Rename section, add diagrams
---
 docs/source/activity_aggr_file.puml                | 27 ++++++++++++
 docs/source/activity_aggr_lines.puml               | 36 ++++++++++++++++
 docs/source/activity_scaling_as_torflow.puml       | 35 ++++++++++++++++
 docs/source/generator.rst                          | 20 +++++++--
 docs/source/images/activity_aggr_file.svg          | 40 ++++++++++++++++++
 docs/source/images/activity_aggr_lines.svg         | 49 ++++++++++++++++++++++
 docs/source/images/activity_scaling_as_torflow.svg | 47 +++++++++++++++++++++
 7 files changed, 251 insertions(+), 3 deletions(-)

diff --git a/docs/source/activity_aggr_file.puml b/docs/source/activity_aggr_file.puml
new file mode 100644
index 0000000..04be253
--- /dev/null
+++ b/docs/source/activity_aggr_file.puml
@@ -0,0 +1,27 @@
+ at startuml
+
+title Activity diagram sbws relays exclusion (V3BWFile.from_results)
+
+start
+:router_statuses_d;
+while (results.items()?)
+    :line, reason = V3BWLine.from_results();
+    if (not reason?) then (yes)
+        :bwlines_raw.append(line);
+    else (no)
+        :bw_lines_excluded.append(line);
+        :exclusion_dict[reason] = exclusion_dict.get(reason, 0) + 1;
+    endif
+endwhile
+:header.add_relays_excluded_counters(exclusion_dict);
+if (not bw_lines_raw?) then (yes)
+    :return (header, bw_lines_excluded);
+    stop
+endif
+if (scaling_method == TORFLOW?) then (yes)
+    :bw_lines = cls.bw_torflow_scale();
+endif
+:return (header, bw_lines + bw_lines_excluded);
+stop
+
+ at enduml
diff --git a/docs/source/activity_aggr_lines.puml b/docs/source/activity_aggr_lines.puml
new file mode 100644
index 0000000..b9b9e42
--- /dev/null
+++ b/docs/source/activity_aggr_lines.puml
@@ -0,0 +1,36 @@
+ at startuml
+
+title Activity diagram sbws results exclussion and aggregation (V3BWLine.from_results)
+
+start
+:success_results;
+if (not success_results?) then (yes)
+    :return (, exclusion_reason);
+    stop
+endif
+:results_away;
+if (not results_away?) then (yes)
+    :return (, exclusion_reason);
+    stop
+endif
+:results_recent;
+if (not results_recent?) then (yes)
+    :return (, exclusion_reason);
+    stop
+endif
+if (node_id in router_statuses_d?) then (yes)
+    :consensus_bandwidth;
+else (no)
+    :consensus_bandwidth;
+endif
+:obs_last;
+if (obs_last is None and consensus_bandwidth is None?) then (yes)
+    :return(cls(node_id, 1), "no_consensus_no_observed_bw");
+    stop
+endif
+:bw;
+:kwargs[...];
+:return (node_id, bw, **kwargs), None;
+stop
+
+ at enduml
diff --git a/docs/source/activity_scaling_as_torflow.puml b/docs/source/activity_scaling_as_torflow.puml
new file mode 100644
index 0000000..65a4457
--- /dev/null
+++ b/docs/source/activity_scaling_as_torflow.puml
@@ -0,0 +1,35 @@
+ at startuml
+
+title Activity diagram sbws bw_torflow_scale
+
+start
+'bw_lines: the relays' raw measurements
+:mu = mean([l.bw_mean for l in bw_lines]);
+:muf = mean([l.bw_filt for l in bw_lines]);
+:sum_bw = 0;
+while (for l in bw_lines?)
+    :bw_obs;
+    :desc_bw = min(desc_bw_obs, l.desc_bw_bur, l.desc_bw_avg);
+    :min_bandwidth = min(desc_bw, l.consensus_bandwidth);
+    :ratio_stream = l.bw_mean / mu;
+    :ratio_stream_filtered = l.bw_filt / muf;
+    :ratio = max(ratio_stream, ratio_stream_filtered);
+    :l.bw = ratio * min_bandwidth;
+    if (router_statuses_d?) then (yes)
+        if (l.node_id in router_statuses_d?) then (yes)
+            :sum_bw += l.bw;
+        endif
+    else (no)
+        :sum_bw += l.bw;
+    endif
+endwhile
+:hlimit = sum_bw * cap;
+while (for l in bw_lines?)
+    :bw_scaled = min(hlimit, l.bw);
+    :l.bw = kb_round_x_sig_dig(bw_scaled, digits=num_round_dig);
+endwhile
+:return sorted(bw_lines_tf, key=lambda x: x.bw, reverse=reverse);
+stop
+
+footer last updated 2021-01-08
+ at enduml
diff --git a/docs/source/generator.rst b/docs/source/generator.rst
index ef94703..7d43d33 100644
--- a/docs/source/generator.rst
+++ b/docs/source/generator.rst
@@ -1,9 +1,9 @@
 .. _generator:
 
-How the Bandwidth File is generated
-===================================
+How aggregation and scaling works
+=================================
 
-.. seealso:: :ref:`scanner`.
+.. seealso:: :ref:`scanner` (scanner part).
 
 Every hour, the generator:
 
@@ -14,6 +14,8 @@ Every hour, the generator:
 
 Source code: :func:`sbws.lib.v3bwfile.V3BWFile.from_results`
 
+.. _filtering-measurements:
+
 Filtering the bandwidth measurements
 -------------------------------------
 
@@ -32,14 +34,26 @@ a percententage (currently 60%) than the number of relays in the consensus,
 additional Header Lines MUST be added (see XXX) to the Bandwith File and the
 relays SHOULD NOT be included.
 
+.. image:: ./images/activity_aggr_file.svg
+
+.. image:: ./images/activity_aggr_lines.svg
+
+.. _scaling-the-bandwidth-measurements:
+
 Scaling the bandwidth measurements
 ------------------------------------
 
 Consensus bandwidth obtained by new implementations MUST be comparable to the
 consensus bandwidth, therefore they MUST implement torflow_scaling_.
+
 The bandwidth_file_spec_ appendix B describes torflow scaling and a linear
 scaling method.
 
+.. image:: ./images/activity_scaling_as_torflow.svg
+
+.. seealso:: :ref:`torflow_aggr` and :ref:`differences`.
+
+
 Writing the bandwidth file
 ---------------------------
 
diff --git a/docs/source/images/activity_aggr_file.svg b/docs/source/images/activity_aggr_file.svg
new file mode 100644
index 0000000..34d0aed
--- /dev/null
+++ b/docs/source/images/activity_aggr_file.svg
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="874px" preserveAspectRatio="none" style="width:663px;height:874px;" version="1.1" viewBox="0 0 663 874" width="663px" zoomAndPan="magnify"><defs><filter height="300%" id="f1enb2bzhjec9f" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><text fill="#000000" font-family="sans-serif" font-size="18" lengthAdjust="spacingAndGlyphs" textLength="547" x="57" y="26.708">Activity diagram sbws relays exclusion V3BWFile.from_results</text><ellipse cx="278.25" cy="40.9531" fill="#000000" filter="url(#f1enb2bz
 hjec9f)" rx="10" ry="10" style="stroke: none; stroke-width: 1.0;"/><rect fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="134" x="211.25" y="70.9531"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="114" x="221.25" y="92.0918">router_statuses_d</text><rect fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="263" x="146.75" y="168.9219"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="243" x="156.75" y="190.0605">line, reason = V3BWLine.from_results()</text><polygon fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" points="244.25,222.8906,312.25,222.8906,324.25,234.8906,312.25,246.8906,244.25,246.8906,232.25,234.8906,244.25,222.8906" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="san
 s-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="68" x="244.25" y="238.6987">not reason?</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="212.25" y="232.2964">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="14" x="324.25" y="232.2964">no</text><rect fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="178" x="38" y="256.8906"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="158" x="48" y="278.0293">bwlines_raw.append(line)</text><rect fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="218" x="320.5" y="256.8906"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength=
 "198" x="330.5" y="278.0293">bw_lines_excluded.append(line)</text><rect fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="387" x="236" y="310.8594"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="367" x="246" y="331.998">exclusion_dict[reason] = exclusion_dict.get(reason, 0) + 1</text><polygon fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" points="278.25,350.8281,290.25,362.8281,278.25,374.8281,266.25,362.8281,278.25,350.8281" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" points="233.25,124.9219,323.25,124.9219,335.25,136.9219,323.25,148.9219,233.25,148.9219,221.25,136.9219,233.25,124.9219" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="90" x="233.25" y="140.73">results.items()?</text><rect fi
 ll="#FEFECE" filter="url(#f1enb2bzhjec9f)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="357" x="99.75" y="416.8281"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="337" x="109.75" y="437.9668">header.add_relays_excluded_counters(exclusion_dict)</text><rect fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="240" x="158.25" y="519.1992"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="220" x="168.25" y="540.3379">return (header, bw_lines_excluded)</text><ellipse cx="278.25" cy="590.6836" fill="none" filter="url(#f1enb2bzhjec9f)" rx="10" ry="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="278.75" cy="591.1836" fill="#000000" filter="url(#f1enb2bzhjec9f)" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><polygon fill="#FEFECE" fil
 ter="url(#f1enb2bzhjec9f)" points="226.25,470.7969,330.25,470.7969,342.25,482.7969,330.25,494.7969,226.25,494.7969,214.25,482.7969,226.25,470.7969" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="282.25" y="505.0073">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="104" x="226.25" y="486.605">not bw_lines_raw?</text><rect fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="225" x="165.75" y="691.0859"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="205" x="175.75" y="712.2246">bw_lines = cls.bw_torflow_scale()</text><polygon fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" points="191.25,642.6836,365.25,642.6836,377.25,654.6836,365.25,666.6836,191.25,666.6836,179.25,654.6836,191
 .25,642.6836" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="282.25" y="676.894">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="174" x="191.25" y="658.4917">scaling_method == TORFLOW?</text><polygon fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" points="278.25,745.0547,290.25,757.0547,278.25,769.0547,266.25,757.0547,278.25,745.0547" style="stroke: #A80036; stroke-width: 1.5;"/><rect fill="#FEFECE" filter="url(#f1enb2bzhjec9f)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="310" x="123.25" y="789.0547"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="290" x="133.25" y="810.1934">return (header, bw_lines + bw_lines_excluded)</text><ellipse cx="278.25" cy="853.0234" fill="none" filter="url(#f1enb2bzhjec9f)" rx="10" r
 y="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="278.75" cy="853.5234" fill="#000000" filter="url(#f1enb2bzhjec9f)" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="50.9531" y2="70.9531"/><polygon fill="#A80036" points="274.25,60.9531,278.25,70.9531,282.25,60.9531,278.25,64.9531" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="429.5" x2="429.5" y1="290.8594" y2="310.8594"/><polygon fill="#A80036" points="425.5,300.8594,429.5,310.8594,433.5,300.8594,429.5,304.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="232.25" x2="127" y1="234.8906" y2="234.8906"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="127" x2="127" y1="234.8906" y2="256.8906"/><polygon fill="#A80036" points="123,246.8906,127,256.8906,131,246.8906,127,250.8906" style="stroke: #A80036; stroke-width: 1.0;"/><lin
 e style="stroke: #A80036; stroke-width: 1.5;" x1="324.25" x2="429.5" y1="234.8906" y2="234.8906"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="429.5" x2="429.5" y1="234.8906" y2="256.8906"/><polygon fill="#A80036" points="425.5,246.8906,429.5,256.8906,433.5,246.8906,429.5,250.8906" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="127" x2="127" y1="290.8594" y2="362.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="127" x2="266.25" y1="362.8281" y2="362.8281"/><polygon fill="#A80036" points="256.25,358.8281,266.25,362.8281,256.25,366.8281,260.25,362.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="429.5" x2="429.5" y1="344.8281" y2="362.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="429.5" x2="290.25" y1="362.8281" y2="362.8281"/><polygon fill="#A80036" points="300.25,358.8281,290.25,362.8281,300.25,366.8281,296.25,362.8281" style="stroke: #A8003
 6; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="202.8906" y2="222.8906"/><polygon fill="#A80036" points="274.25,212.8906,278.25,222.8906,282.25,212.8906,278.25,216.8906" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="148.9219" y2="168.9219"/><polygon fill="#A80036" points="274.25,158.9219,278.25,168.9219,282.25,158.9219,278.25,162.9219" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="374.8281" y2="384.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="637" y1="384.8281" y2="384.8281"/><polygon fill="#A80036" points="633,269.875,637,259.875,641,269.875,637,265.875" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="637" x2="637" y1="136.9219" y2="384.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="637
 " x2="335.25" y1="136.9219" y2="136.9219"/><polygon fill="#A80036" points="345.25,132.9219,335.25,136.9219,345.25,140.9219,341.25,136.9219" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="221.25" x2="24" y1="136.9219" y2="136.9219"/><polygon fill="#A80036" points="20,255.875,24,265.875,28,255.875,24,259.875" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="24" x2="24" y1="136.9219" y2="396.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="24" x2="278.25" y1="396.8281" y2="396.8281"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="396.8281" y2="416.8281"/><polygon fill="#A80036" points="274.25,406.8281,278.25,416.8281,282.25,406.8281,278.25,410.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="104.9219" y2="124.9219"/><polygon fill="#A80036" points="274.25,114.9219,2
 78.25,124.9219,282.25,114.9219,278.25,118.9219" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="553.168" y2="580.6836"/><polygon fill="#A80036" points="274.25,570.6836,278.25,580.6836,282.25,570.6836,278.25,574.6836" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="494.7969" y2="519.1992"/><polygon fill="#A80036" points="274.25,509.1992,278.25,519.1992,282.25,509.1992,278.25,513.1992" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="342.25" x2="408.25" y1="482.7969" y2="482.7969"/><polygon fill="#A80036" points="404.25,550.6836,408.25,560.6836,412.25,550.6836,408.25,554.6836" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="408.25" x2="408.25" y1="482.7969" y2="622.6836"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="408.25" x2="2
 78.25" y1="622.6836" y2="622.6836"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="622.6836" y2="642.6836"/><polygon fill="#A80036" points="274.25,632.6836,278.25,642.6836,282.25,632.6836,278.25,636.6836" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="450.7969" y2="470.7969"/><polygon fill="#A80036" points="274.25,460.7969,278.25,470.7969,282.25,460.7969,278.25,464.7969" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="666.6836" y2="691.0859"/><polygon fill="#A80036" points="274.25,681.0859,278.25,691.0859,282.25,681.0859,278.25,685.0859" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="377.25" x2="400.75" y1="654.6836" y2="654.6836"/><polygon fill="#A80036" points="396.75,698.0703,400.75,708.0703,404.75,698.0703,400.75,702.0703" style="stroke: #A80036; st
 roke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="400.75" x2="400.75" y1="654.6836" y2="757.0547"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="400.75" x2="290.25" y1="757.0547" y2="757.0547"/><polygon fill="#A80036" points="300.25,753.0547,290.25,757.0547,300.25,761.0547,296.25,757.0547" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="725.0547" y2="745.0547"/><polygon fill="#A80036" points="274.25,735.0547,278.25,745.0547,282.25,735.0547,278.25,739.0547" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="769.0547" y2="789.0547"/><polygon fill="#A80036" points="274.25,779.0547,278.25,789.0547,282.25,779.0547,278.25,783.0547" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="278.25" x2="278.25" y1="823.0234" y2="843.0234"/><polygon fill="#A80036" points="274.2
 5,833.0234,278.25,843.0234,282.25,833.0234,278.25,837.0234" style="stroke: #A80036; stroke-width: 1.0;"/><!--
+ at startuml
+
+title Activity diagram sbws relays exclusion V3BWFile.from_results
+
+start
+:router_statuses_d;
+while (results.items()?)
+    :line, reason = V3BWLine.from_results();
+    if (not reason?) then (yes)
+        :bwlines_raw.append(line);
+    else (no)
+        :bw_lines_excluded.append(line);
+        :exclusion_dict[reason] = exclusion_dict.get(reason, 0) + 1;
+    endif
+endwhile
+:header.add_relays_excluded_counters(exclusion_dict);
+if (not bw_lines_raw?) then (yes)
+    :return (header, bw_lines_excluded);
+    stop
+endif
+if (scaling_method == TORFLOW?) then (yes)
+    :bw_lines = cls.bw_torflow_scale();
+endif
+:return (header, bw_lines + bw_lines_excluded);
+stop
+
+ at enduml
+
+PlantUML version 1.2018.13(Mon Nov 26 17:11:51 GMT 2018)
+(GPL source distribution)
+Java Runtime: OpenJDK Runtime Environment
+JVM: OpenJDK 64-Bit Server VM
+Java Version: 11.0.9.1+1-post-Debian-1deb10u2
+Operating System: Linux
+OS Version: 4.19.0-13-amd64
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file
diff --git a/docs/source/images/activity_aggr_lines.svg b/docs/source/images/activity_aggr_lines.svg
new file mode 100644
index 0000000..789a97b
--- /dev/null
+++ b/docs/source/images/activity_aggr_lines.svg
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="1285px" preserveAspectRatio="none" style="width:430px;height:1285px;" version="1.1" viewBox="0 0 430 1285" width="430px" zoomAndPan="magnify"><defs><filter height="300%" id="fsu3zpce5sdbv" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><text fill="#000000" font-family="sans-serif" font-size="18" lengthAdjust="spacingAndGlyphs" textLength="406" x="12" y="26.708">Activity diagram sbws V3BWLine.from_results</text><ellipse cx="203" cy="40.9531" fill="#000000" filter="url(#fsu3zpce5sdbv)" rx="10" ry
 ="10" style="stroke: none; stroke-width: 1.0;"/><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="120" x="143" y="70.9531"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="100" x="153" y="92.0918">success_results</text><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="189" x="108.5" y="173.3242"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="169" x="118.5" y="194.4629">return (, exclusion_reason)</text><ellipse cx="203" cy="244.8086" fill="none" filter="url(#fsu3zpce5sdbv)" rx="10" ry="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="203.5" cy="245.3086" fill="#000000" filter="url(#fsu3zpce5sdbv)" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><polygon fill="#FEFECE" filter=
 "url(#fsu3zpce5sdbv)" points="142.5,124.9219,263.5,124.9219,275.5,136.9219,263.5,148.9219,142.5,148.9219,130.5,136.9219,142.5,124.9219" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="207" y="159.1323">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="121" x="142.5" y="140.73">not success_results?</text><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="100" x="153" y="296.8086"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="80" x="163" y="317.9473">results_away</text><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="189" x="108.5" y="399.1797"/><text fill="#000000" font-family="san
 s-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="169" x="118.5" y="420.3184">return (, exclusion_reason)</text><ellipse cx="203" cy="470.6641" fill="none" filter="url(#fsu3zpce5sdbv)" rx="10" ry="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="203.5" cy="471.1641" fill="#000000" filter="url(#fsu3zpce5sdbv)" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><polygon fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" points="151.5,350.7773,254.5,350.7773,266.5,362.7773,254.5,374.7773,151.5,374.7773,139.5,362.7773,151.5,350.7773" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="207" y="384.9878">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="103" x="151.5" y="366.5854">not results_away?</text><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" sty
 le="stroke: #A80036; stroke-width: 1.5;" width="110" x="148" y="522.6641"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="90" x="158" y="543.8027">results_recent</text><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="189" x="108.5" y="625.0352"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="169" x="118.5" y="646.1738">return (, exclusion_reason)</text><ellipse cx="203" cy="696.5195" fill="none" filter="url(#fsu3zpce5sdbv)" rx="10" ry="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="203.5" cy="697.0195" fill="#000000" filter="url(#fsu3zpce5sdbv)" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><polygon fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" points="148,576.6328,258,576.6328,270,588.6328,258,600.6328,148,600.6328,136,588.6328,148,576.6328" style="stroke: #
 A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="207" y="610.8433">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="110" x="148" y="592.4409">not results_recent?</text><polygon fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" points="117,748.5195,289,748.5195,301,760.5195,289,772.5195,117,772.5195,105,760.5195,117,748.5195" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="172" x="117" y="764.3276">node_id in router_statuses_d?</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="85" y="757.9253">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="14" x="301" y="757.9253">no</text><rect fill="#FEFECE" filter=
 "url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="159" x="15.5" y="782.5195"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="139" x="25.5" y="803.6582">consensus_bandwidth</text><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="159" x="231.5" y="782.5195"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="139" x="241.5" y="803.6582">consensus_bandwidth</text><polygon fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" points="203,822.4883,215,834.4883,203,846.4883,191,834.4883,203,822.4883" style="stroke: #A80036; stroke-width: 1.5;"/><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="72" x="167" y="866.4883"/><text fill="#000000" font-family="sans-
 serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="52" x="177" y="887.627">obs_last</text><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="378" x="14" y="968.8594"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="358" x="24" y="989.998">return(cls(node_id, 1), "no_consensus_no_observed_bw")</text><ellipse cx="203" cy="1040.3438" fill="none" filter="url(#fsu3zpce5sdbv)" rx="10" ry="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="203.5" cy="1040.8438" fill="#000000" filter="url(#fsu3zpce5sdbv)" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><polygon fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" points="51.5,920.457,354.5,920.457,366.5,932.457,354.5,944.457,51.5,944.457,39.5,932.457,51.5,920.457" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" length
 Adjust="spacingAndGlyphs" textLength="20" x="207" y="954.6675">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="303" x="51.5" y="936.2651">obs_last is None and consensus_bandwidth is None?</text><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="37" x="184.5" y="1092.3438"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="17" x="194.5" y="1113.4824">bw</text><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="86" x="160" y="1146.3125"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="66" x="170" y="1167.4512">kwargs[...]</text><rect fill="#FEFECE" filter="url(#fsu3zpce5sdbv)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; st
 roke-width: 1.5;" width="252" x="77" y="1200.2813"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="232" x="87" y="1221.4199">return (node_id, bw, **kwargs), None</text><ellipse cx="203" cy="1264.25" fill="none" filter="url(#fsu3zpce5sdbv)" rx="10" ry="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="203.5" cy="1264.75" fill="#000000" filter="url(#fsu3zpce5sdbv)" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="50.9531" y2="70.9531"/><polygon fill="#A80036" points="199,60.9531,203,70.9531,207,60.9531,203,64.9531" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="207.293" y2="234.8086"/><polygon fill="#A80036" points="199,224.8086,203,234.8086,207,224.8086,203,228.8086" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203"
  x2="203" y1="148.9219" y2="173.3242"/><polygon fill="#A80036" points="199,163.3242,203,173.3242,207,163.3242,203,167.3242" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="275.5" x2="307.5" y1="136.9219" y2="136.9219"/><polygon fill="#A80036" points="303.5,204.8086,307.5,214.8086,311.5,204.8086,307.5,208.8086" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="307.5" x2="307.5" y1="136.9219" y2="276.8086"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="307.5" x2="203" y1="276.8086" y2="276.8086"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="276.8086" y2="296.8086"/><polygon fill="#A80036" points="199,286.8086,203,296.8086,207,286.8086,203,290.8086" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="104.9219" y2="124.9219"/><polygon fill="#A80036" points="199,114.9219,203,124.9219,207,114
 .9219,203,118.9219" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="433.1484" y2="460.6641"/><polygon fill="#A80036" points="199,450.6641,203,460.6641,207,450.6641,203,454.6641" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="374.7773" y2="399.1797"/><polygon fill="#A80036" points="199,389.1797,203,399.1797,207,389.1797,203,393.1797" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="266.5" x2="307.5" y1="362.7773" y2="362.7773"/><polygon fill="#A80036" points="303.5,430.6641,307.5,440.6641,311.5,430.6641,307.5,434.6641" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="307.5" x2="307.5" y1="362.7773" y2="502.6641"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="307.5" x2="203" y1="502.6641" y2="502.6641"/><line style="stroke: #A80036; stroke-wi
 dth: 1.5;" x1="203" x2="203" y1="502.6641" y2="522.6641"/><polygon fill="#A80036" points="199,512.6641,203,522.6641,207,512.6641,203,516.6641" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="330.7773" y2="350.7773"/><polygon fill="#A80036" points="199,340.7773,203,350.7773,207,340.7773,203,344.7773" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="659.0039" y2="686.5195"/><polygon fill="#A80036" points="199,676.5195,203,686.5195,207,676.5195,203,680.5195" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="600.6328" y2="625.0352"/><polygon fill="#A80036" points="199,615.0352,203,625.0352,207,615.0352,203,619.0352" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="270" x2="307.5" y1="588.6328" y2="588.6328"/><polygon fill="#A80036" point
 s="303.5,656.5195,307.5,666.5195,311.5,656.5195,307.5,660.5195" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="307.5" x2="307.5" y1="588.6328" y2="728.5195"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="307.5" x2="203" y1="728.5195" y2="728.5195"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="728.5195" y2="748.5195"/><polygon fill="#A80036" points="199,738.5195,203,748.5195,207,738.5195,203,742.5195" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="556.6328" y2="576.6328"/><polygon fill="#A80036" points="199,566.6328,203,576.6328,207,566.6328,203,570.6328" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="105" x2="95" y1="760.5195" y2="760.5195"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="95" x2="95" y1="760.5195" y2="782.5195"/><polygon fill="#A80036" points="91,772.5195
 ,95,782.5195,99,772.5195,95,776.5195" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="301" x2="311" y1="760.5195" y2="760.5195"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="311" x2="311" y1="760.5195" y2="782.5195"/><polygon fill="#A80036" points="307,772.5195,311,782.5195,315,772.5195,311,776.5195" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="95" x2="95" y1="816.4883" y2="834.4883"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="95" x2="191" y1="834.4883" y2="834.4883"/><polygon fill="#A80036" points="181,830.4883,191,834.4883,181,838.4883,185,834.4883" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="311" x2="311" y1="816.4883" y2="834.4883"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="311" x2="215" y1="834.4883" y2="834.4883"/><polygon fill="#A80036" points="225,830.4883,215,834.4883,225,838.4883,221,
 834.4883" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="846.4883" y2="866.4883"/><polygon fill="#A80036" points="199,856.4883,203,866.4883,207,856.4883,203,860.4883" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="1002.8281" y2="1030.3438"/><polygon fill="#A80036" points="199,1020.3438,203,1030.3438,207,1020.3438,203,1024.3438" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="944.457" y2="968.8594"/><polygon fill="#A80036" points="199,958.8594,203,968.8594,207,958.8594,203,962.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="366.5" x2="402" y1="932.457" y2="932.457"/><polygon fill="#A80036" points="398,1000.3438,402,1010.3438,406,1000.3438,402,1004.3438" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80
 036; stroke-width: 1.5;" x1="402" x2="402" y1="932.457" y2="1072.3438"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="402" x2="203" y1="1072.3438" y2="1072.3438"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="1072.3438" y2="1092.3438"/><polygon fill="#A80036" points="199,1082.3438,203,1092.3438,207,1082.3438,203,1086.3438" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="900.457" y2="920.457"/><polygon fill="#A80036" points="199,910.457,203,920.457,207,910.457,203,914.457" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="1126.3125" y2="1146.3125"/><polygon fill="#A80036" points="199,1136.3125,203,1146.3125,207,1136.3125,203,1140.3125" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="1180.2813" y2="1200.2813"/><polygon fill="#A80036" points="199,1190
 .2813,203,1200.2813,207,1190.2813,203,1194.2813" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="203" x2="203" y1="1234.25" y2="1254.25"/><polygon fill="#A80036" points="199,1244.25,203,1254.25,207,1244.25,203,1248.25" style="stroke: #A80036; stroke-width: 1.0;"/><!--
+ at startuml
+
+title Activity diagram sbws V3BWLine.from_results
+
+start
+:success_results;
+if (not success_results?) then (yes)
+    :return (, exclusion_reason);
+    stop
+endif
+:results_away;
+if (not results_away?) then (yes)
+    :return (, exclusion_reason);
+    stop
+endif
+:results_recent;
+if (not results_recent?) then (yes)
+    :return (, exclusion_reason);
+    stop
+endif
+if (node_id in router_statuses_d?) then (yes)
+    :consensus_bandwidth;
+else (no)
+    :consensus_bandwidth;
+endif
+:obs_last;
+if (obs_last is None and consensus_bandwidth is None?) then (yes)
+    :return(cls(node_id, 1), "no_consensus_no_observed_bw");
+    stop
+endif
+:bw;
+:kwargs[...];
+:return (node_id, bw, **kwargs), None;
+stop
+
+ at enduml
+
+PlantUML version 1.2018.13(Mon Nov 26 17:11:51 GMT 2018)
+(GPL source distribution)
+Java Runtime: OpenJDK Runtime Environment
+JVM: OpenJDK 64-Bit Server VM
+Java Version: 11.0.9.1+1-post-Debian-1deb10u2
+Operating System: Linux
+OS Version: 4.19.0-13-amd64
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file
diff --git a/docs/source/images/activity_scaling_as_torflow.svg b/docs/source/images/activity_scaling_as_torflow.svg
new file mode 100644
index 0000000..822bd75
--- /dev/null
+++ b/docs/source/images/activity_scaling_as_torflow.svg
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="1237px" preserveAspectRatio="none" style="width:483px;height:1237px;" version="1.1" viewBox="0 0 483 1237" width="483px" zoomAndPan="magnify"><defs><filter height="300%" id="fq8tw0sgtkabn" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><text fill="#000000" font-family="sans-serif" font-size="18" lengthAdjust="spacingAndGlyphs" textLength="352" x="64.75" y="26.708">Activity diagram sbws bw_torflow_scale</text><ellipse cx="244.5" cy="40.9531" fill="#000000" filter="url(#fq8tw0sgtkabn)" rx="10" ry
 ="10" style="stroke: none; stroke-width: 1.0;"/><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="276" x="106.5" y="70.9531"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="256" x="116.5" y="92.0918">mu = mean([l.bw_mean for l in bw_lines])</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="260" x="114.5" y="124.9219"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="240" x="124.5" y="146.0605">muf = mean([l.bw_filt for l in bw_lines])</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="95" x="197" y="178.8906"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs"
  textLength="75" x="207" y="200.0293">sum_bw = 0</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="66" x="211.5" y="276.8594"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="46" x="221.5" y="297.998">bw_obs</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="396" x="46.5" y="330.8281"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="376" x="56.5" y="351.9668">desc_bw = min(desc_bw_obs, l.desc_bw_bur, l.desc_bw_avg)</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="370" x="59.5" y="384.7969"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="
 350" x="69.5" y="405.9355">min_bandwidth = min(desc_bw, l.consensus_bandwidth)</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="213" x="138" y="438.7656"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="193" x="148" y="459.9043">ratio_stream = l.bw_mean / mu</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="247" x="121" y="492.7344"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="227" x="131" y="513.873">ratio_stream_filtered = l.bw_filt / muf</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="318" x="85.5" y="558.7695"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust
 ="spacingAndGlyphs" textLength="298" x="95.5" y="579.9082">ratio = max(ratio_stream, ratio_stream_filtered)</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="198" x="145.5" y="612.7383"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="178" x="155.5" y="633.877">l.bw = ratio * min_bandwidth</text><polygon fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" points="189.5,666.707,299.5,666.707,311.5,678.707,299.5,690.707,189.5,690.707,177.5,678.707,189.5,666.707" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="110" x="189.5" y="682.5151">router_statuses_d?</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="157.5" y="676.1128">yes</text><text fill="#000000" font-family="sans-serif
 " font-size="11" lengthAdjust="spacingAndGlyphs" textLength="14" x="311.5" y="676.1128">no</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="121" x="87" y="749.1094"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="101" x="97" y="770.248">sum_bw += l.bw</text><polygon fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" points="58,700.707,237,700.707,249,712.707,237,724.707,58,724.707,46,712.707,58,700.707" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="20" x="151.5" y="734.9175">yes</text><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="179" x="58" y="716.5151">l.node_id in router_statuses_d?</text><polygon fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" points="147.5,803.0781,159.5,815.078
 1,147.5,827.0781,135.5,815.0781,147.5,803.0781" style="stroke: #A80036; stroke-width: 1.5;"/><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="121" x="281" y="700.707"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="101" x="291" y="721.8457">sum_bw += l.bw</text><polygon fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" points="244.5,833.0781,256.5,845.0781,244.5,857.0781,232.5,845.0781,244.5,833.0781" style="stroke: #A80036; stroke-width: 1.5;"/><polygon fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" points="196.5,232.8594,292.5,232.8594,304.5,244.8594,292.5,256.8594,196.5,256.8594,184.5,244.8594,196.5,232.8594" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="96" x="196.5" y="248.6675">for l in bw_lines?</text><rect fill="#FEFECE" filter="url(#fq8
 tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="157" x="166" y="899.0781"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="137" x="176" y="920.2168">hlimit = sum_bw * cap</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="199" x="145" y="997.0469"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="179" x="155" y="1018.1855">bw_scaled = min(hlimit, l.bw)</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="402" x="43.5" y="1066.0156"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="382" x="53.5" y="1087.1543">l.bw = kb_round_x_sig_dig(bw_scaled, digits=num_round_dig)</text><polygon fil
 l="#FEFECE" filter="url(#fq8tw0sgtkabn)" points="196.5,953.0469,292.5,953.0469,304.5,965.0469,292.5,977.0469,196.5,977.0469,184.5,965.0469,196.5,953.0469" style="stroke: #A80036; stroke-width: 1.5;"/><text fill="#000000" font-family="sans-serif" font-size="11" lengthAdjust="spacingAndGlyphs" textLength="96" x="196.5" y="968.855">for l in bw_lines?</text><rect fill="#FEFECE" filter="url(#fq8tw0sgtkabn)" height="33.9688" rx="12.5" ry="12.5" style="stroke: #A80036; stroke-width: 1.5;" width="423" x="33" y="1141.9844"/><text fill="#000000" font-family="sans-serif" font-size="12" lengthAdjust="spacingAndGlyphs" textLength="403" x="43" y="1163.123">return sorted(bw_lines_tf, key=lambda x: x.bw, reverse=reverse)</text><ellipse cx="244.5" cy="1205.9531" fill="none" filter="url(#fq8tw0sgtkabn)" rx="10" ry="10" style="stroke: #000000; stroke-width: 1.0;"/><ellipse cx="245" cy="1206.4531" fill="#000000" filter="url(#fq8tw0sgtkabn)" rx="6" ry="6" style="stroke: none; stroke-width: 1.0;"/><line 
 style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="50.9531" y2="70.9531"/><polygon fill="#A80036" points="240.5,60.9531,244.5,70.9531,248.5,60.9531,244.5,64.9531" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="104.9219" y2="124.9219"/><polygon fill="#A80036" points="240.5,114.9219,244.5,124.9219,248.5,114.9219,244.5,118.9219" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="158.8906" y2="178.8906"/><polygon fill="#A80036" points="240.5,168.8906,244.5,178.8906,248.5,168.8906,244.5,172.8906" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="310.8281" y2="330.8281"/><polygon fill="#A80036" points="240.5,320.8281,244.5,330.8281,248.5,320.8281,244.5,324.8281" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1=
 "244.5" x2="244.5" y1="364.7969" y2="384.7969"/><polygon fill="#A80036" points="240.5,374.7969,244.5,384.7969,248.5,374.7969,244.5,378.7969" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="418.7656" y2="438.7656"/><polygon fill="#A80036" points="240.5,428.7656,244.5,438.7656,248.5,428.7656,244.5,432.7656" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="472.7344" y2="492.7344"/><polygon fill="#A80036" points="240.5,482.7344,244.5,492.7344,248.5,482.7344,244.5,486.7344" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="526.7031" y2="558.7695"/><polygon fill="#A80036" points="240.5,548.7695,244.5,558.7695,248.5,548.7695,244.5,552.7695" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="592.7383" y2="612.
 7383"/><polygon fill="#A80036" points="240.5,602.7383,244.5,612.7383,248.5,602.7383,244.5,606.7383" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="147.5" x2="147.5" y1="724.707" y2="749.1094"/><polygon fill="#A80036" points="143.5,739.1094,147.5,749.1094,151.5,739.1094,147.5,743.1094" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="249" x2="261" y1="712.707" y2="712.707"/><polygon fill="#A80036" points="257,756.0938,261,766.0938,265,756.0938,261,760.0938" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="261" x2="261" y1="712.707" y2="815.0781"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="261" x2="159.5" y1="815.0781" y2="815.0781"/><polygon fill="#A80036" points="169.5,811.0781,159.5,815.0781,169.5,819.0781,165.5,815.0781" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="14
 7.5" x2="147.5" y1="783.0781" y2="803.0781"/><polygon fill="#A80036" points="143.5,793.0781,147.5,803.0781,151.5,793.0781,147.5,797.0781" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="177.5" x2="147.5" y1="678.707" y2="678.707"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="147.5" x2="147.5" y1="678.707" y2="700.707"/><polygon fill="#A80036" points="143.5,690.707,147.5,700.707,151.5,690.707,147.5,694.707" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="311.5" x2="341.5" y1="678.707" y2="678.707"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="341.5" x2="341.5" y1="678.707" y2="700.707"/><polygon fill="#A80036" points="337.5,690.707,341.5,700.707,345.5,690.707,341.5,694.707" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="147.5" x2="147.5" y1="827.0781" y2="845.0781"/><line style="stroke: #A80036; stroke-width: 1.5;"
  x1="147.5" x2="232.5" y1="845.0781" y2="845.0781"/><polygon fill="#A80036" points="222.5,841.0781,232.5,845.0781,222.5,849.0781,226.5,845.0781" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="341.5" x2="341.5" y1="734.6758" y2="845.0781"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="341.5" x2="256.5" y1="845.0781" y2="845.0781"/><polygon fill="#A80036" points="266.5,841.0781,256.5,845.0781,266.5,849.0781,262.5,845.0781" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="646.707" y2="666.707"/><polygon fill="#A80036" points="240.5,656.707,244.5,666.707,248.5,656.707,244.5,660.707" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="256.8594" y2="276.8594"/><polygon fill="#A80036" points="240.5,266.8594,244.5,276.8594,248.5,266.8594,244.5,270.8594" style="stroke: #A80036; stroke-width: 1.
 0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="857.0781" y2="867.0781"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="454.5" y1="867.0781" y2="867.0781"/><polygon fill="#A80036" points="450.5,550.7031,454.5,540.7031,458.5,550.7031,454.5,546.7031" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="454.5" x2="454.5" y1="244.8594" y2="867.0781"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="454.5" x2="304.5" y1="244.8594" y2="244.8594"/><polygon fill="#A80036" points="314.5,240.8594,304.5,244.8594,314.5,248.8594,310.5,244.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="184.5" x2="24" y1="244.8594" y2="244.8594"/><polygon fill="#A80036" points="20,536.7031,24,546.7031,28,536.7031,24,540.7031" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="24" x2="24" y1="244.8594" y2="879.
 0781"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="24" x2="244.5" y1="879.0781" y2="879.0781"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="879.0781" y2="899.0781"/><polygon fill="#A80036" points="240.5,889.0781,244.5,899.0781,248.5,889.0781,244.5,893.0781" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="212.8594" y2="232.8594"/><polygon fill="#A80036" points="240.5,222.8594,244.5,232.8594,248.5,222.8594,244.5,226.8594" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="1031.0156" y2="1066.0156"/><polygon fill="#A80036" points="240.5,1056.0156,244.5,1066.0156,248.5,1056.0156,244.5,1060.0156" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="977.0469" y2="997.0469"/><polygon fill="#A80036" points="240.5,987.0469,244.5,997.0469,248.5,
 987.0469,244.5,991.0469" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="1099.9844" y2="1109.9844"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="457.5" y1="1109.9844" y2="1109.9844"/><polygon fill="#A80036" points="453.5,1046.5156,457.5,1036.5156,461.5,1046.5156,457.5,1042.5156" style="stroke: #A80036; stroke-width: 1.5;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="457.5" x2="457.5" y1="965.0469" y2="1109.9844"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="457.5" x2="304.5" y1="965.0469" y2="965.0469"/><polygon fill="#A80036" points="314.5,961.0469,304.5,965.0469,314.5,969.0469,310.5,965.0469" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="184.5" x2="31.5" y1="965.0469" y2="965.0469"/><polygon fill="#A80036" points="27.5,1032.5156,31.5,1042.5156,35.5,1032.5156,31.5,1036.5156" style="stroke: #A80036; stroke-width: 1.5;"/>
 <line style="stroke: #A80036; stroke-width: 1.5;" x1="31.5" x2="31.5" y1="965.0469" y2="1121.9844"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="31.5" x2="244.5" y1="1121.9844" y2="1121.9844"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="1121.9844" y2="1141.9844"/><polygon fill="#A80036" points="240.5,1131.9844,244.5,1141.9844,248.5,1131.9844,244.5,1135.9844" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="933.0469" y2="953.0469"/><polygon fill="#A80036" points="240.5,943.0469,244.5,953.0469,248.5,943.0469,244.5,947.0469" style="stroke: #A80036; stroke-width: 1.0;"/><line style="stroke: #A80036; stroke-width: 1.5;" x1="244.5" x2="244.5" y1="1175.9531" y2="1195.9531"/><polygon fill="#A80036" points="240.5,1185.9531,244.5,1195.9531,248.5,1185.9531,244.5,1189.9531" style="stroke: #A80036; stroke-width: 1.0;"/><text fill="#888888" font-family="sans-serif" font-size="10" lengt
 hAdjust="spacingAndGlyphs" textLength="119" x="181.25" y="1224.2354">last updated 2021-01-08</text><!--
+ at startuml
+
+title Activity diagram sbws bw_torflow_scale
+
+start
+:mu = mean([l.bw_mean for l in bw_lines]);
+:muf = mean([l.bw_filt for l in bw_lines]);
+:sum_bw = 0;
+while (for l in bw_lines?)
+    :bw_obs;
+    :desc_bw = min(desc_bw_obs, l.desc_bw_bur, l.desc_bw_avg);
+    :min_bandwidth = min(desc_bw, l.consensus_bandwidth);
+    :ratio_stream = l.bw_mean / mu;
+    :ratio_stream_filtered = l.bw_filt / muf;
+    :ratio = max(ratio_stream, ratio_stream_filtered);
+    :l.bw = ratio * min_bandwidth;
+    if (router_statuses_d?) then (yes)
+        if (l.node_id in router_statuses_d?) then (yes)
+            :sum_bw += l.bw;
+        endif
+    else (no)
+        :sum_bw += l.bw;
+    endif
+endwhile
+:hlimit = sum_bw * cap;
+while (for l in bw_lines?)
+    :bw_scaled = min(hlimit, l.bw);
+    :l.bw = kb_round_x_sig_dig(bw_scaled, digits=num_round_dig);
+endwhile
+:return sorted(bw_lines_tf, key=lambda x: x.bw, reverse=reverse);
+stop
+
+footer last updated 2021-01-08
+ at enduml
+
+PlantUML version 1.2018.13(Mon Nov 26 17:11:51 GMT 2018)
+(GPL source distribution)
+Java Runtime: OpenJDK Runtime Environment
+JVM: OpenJDK 64-Bit Server VM
+Java Version: 11.0.9.1+1-post-Debian-1deb10u2
+Operating System: Linux
+OS Version: 4.19.0-13-amd64
+Default Encoding: UTF-8
+Language: en
+Country: US
+--></g></svg>
\ No newline at end of file





More information about the tor-commits mailing list