Loading app.py +1 −57 Original line number Diff line number Diff line Loading @@ -123,63 +123,7 @@ def index(): @app.route('/result.json', methods=['GET']) def json_result(): options = Opt(dict(request.args.items())) if "TESTING_DATAFILE" in app.config and "TESTING" in app.config: stats = compass.RelayStats(options,app.config['TESTING_DATAFILE']) else: stats = compass.RelayStats(options) results = stats.select_relays(stats.relays, options) relays = stats.sort_and_reduce(results, options) return Response(json.dumps(relays, cls=ResultEncoder), mimetype='application/json') @app.route('/result', methods=['GET']) def result(): options = Opt() sort_key = None relays = [] for key, value in request.args.items(): if key == "top": try: options.top = int(value) except: options.top = -1 elif key == "sort": sort_key = value elif key in ["country", "ases"]: if value: setattr(options, key, [value]) else: setattr(options, key, None) elif key == "exits": setattr(options, value, True) else: setattr(options, key, value) stats = compass.RelayStats(options) sorted_groups = stats.format_and_sort_groups(stats.relays, by_country=options.by_country, by_as_number=options.by_as, links=options.links) output_string = stats.print_groups(sorted_groups, options.top, by_country=options.by_country, by_as_number=options.by_as, short=None, links=None) results = parse(output_string, options.by_country or options.by_as, sort_key) if sort_key: for key in sorted(results.iterkeys(), reverse=True): for value in results[key]: relays.append(value) else: relays = results return render_template('result.html', results=relays, grouping=options.by_as or options.by_country) return jsonify({"error": "The Compass service has been partially shut down. See https://trac.torproject.org/projects/tor/ticket/24445."}) if __name__ == '__main__': # Bind to PORT if defined, otherwise default to 5000. Loading static/js/angularize.js +35 −51 Original line number Diff line number Diff line Loading @@ -11,11 +11,6 @@ compassModule.controller('CompassCtrl',function CompassCtrl($scope,$http,$locati $scope.state = "hidden" $scope.query = { exit_filter:"all_relays", links:true, sort:'cw', sort_reverse: true, country: null } /** Watch the location bar to allow us to load saved searches **/ Loading @@ -26,59 +21,48 @@ compassModule.controller('CompassCtrl',function CompassCtrl($scope,$http,$locati } }) /** Make a sorting request /** Make a data request from the form * * Call 'success_cb' if the request is successful */ $scope.ajax_sort = function(sortBy, invert, success_cb) { $scope.query.sort = sortBy $scope.query.sort_reverse = invert //Update the location bar to track sorting $location.search($scope.query) $http.get('result.json',{"params":$scope.query}) .success(function(data) { if (data.results.length > 0) { $scope.data = data $scope.request = function(success_cb) { var rs_query = ""; if (success_cb !== null){ success_cb() if ((typeof $scope.query["country"]) !== "undefined" && $scope.query["country"] !== "") { rs_query += "country:" + $scope.query["country"] + " "; } $('body').animate({scrollTop:$("div#result_table").offset().top},500) if ((typeof $scope.query["ases"]) !== "undefined" && $scope.query["ases"] !== "") { rs_query += "as:" + $scope.query["ases"] + " "; } else { $scope.state = "result_empty" if ((typeof $scope.query["family"]) !== "undefined" && $scope.query["family"] !== "") { rs_query += "family:" + $scope.query["family"] + " "; } }) if ((typeof $scope.query["exits_only"]) !== "undefined" && $scope.query["exits_only"] == true) { rs_query += "flag:exit" + " "; } else if ((typeof $scope.query["guards_only"]) !== "undefined" && $scope.query["guards_only"] == true) { rs_query += "flag:guard" + " "; } /** Make a data request from the form * * Call 'success_cb' if the request is successful */ $scope.request = function(success_cb) { $scope.state = 'loading' var by_country = ((typeof $scope.query["by_country"]) !== "undefined" && $scope.query["by_country"] == true); var by_as = ((typeof $scope.query["by_as"]) !== "undefined" && $scope.query["by_as"] == true); //Set the location bar for this search $location.search($scope.query) var rs_url = "https://atlas.torproject.org/"; $http.get('result.json',{"params":$scope.query}) .success(function(data) { if (data.results.length > 0) { $scope.data = data $scope.state = "loaded" if (success_cb != null){ success_cb() if (!by_country) { if (!by_as) { rs_url += "#search/running:true " + rs_query.trim(); } else { rs_url += "#aggregate/as/" + rs_query.trim(); } $('body').animate({scrollTop:$("div#result_table").offset().top},500) } else { if (!by_as) { rs_url += "#aggregate/cc/" + rs_query.trim(); } else { rs_url += "#aggregate/ascc/" + rs_query.trim(); } else { $scope.state = "result_empty" } }) document.location = rs_url; }; $scope.reset = function() { Loading templates/index.html +29 −144 Original line number Diff line number Diff line Loading @@ -68,28 +68,24 @@ <div class="container" ng-controller="CompassCtrl"> <div class="hero-unit"> <div class="alert alert-danger"> <p>The Tor Metrics team plans to shut down the Compass service at the end of December 2017. Aggregated search functionality has been <p>The Compass service has now been partially shut down. Aggregated search functionality has been integrated into <a href="https://atlas.torproject.org/#aggregate">Relay Search</a> (formerly known as Atlas) to give a unified tool for exploring both single relays and aggregations of relays.<p> exploring both single relays and aggregations of relays. Any queries made will redirect to Relay Search to display results.<p> <p>Please ensure that all the functionality you require is available in Relay Search before Compass is shut down. If any functionality is missing, please <a href="https://trac.torproject.org/projects/tor/newticket?component=Metrics/Atlas&parent=%2324445">file a ticket to request that it be added</a>.</p> <p>This search form will no longer be available from 15th January 2018.</p> </div> <form class="form-horizontal" id="form"> <fieldset> <legend>Compass</legend> <div class="control-group"> <h3> Filter </h3> <label class="control-label" for="inactive">Inactive</label> <div class="controls"> <label class="checkbox"> <input type="checkbox" id="inactive" value="True" name="inactive" ng-model='query.inactive'> include relays in selection that aren't currently running </label> </div> <label class="control-label" for="guards">Guards</label> <div class="controls"> <label class="checkbox"> Loading Loading @@ -118,36 +114,13 @@ <label class="control-label" for="cc">Country</label> <div class="controls"> <select id="country" name="country" ng-model='query.country' ui-select2 multiple data-placeholder="Germany"> ui-select2 data-placeholder="Germany"> <option value="">Any</option> <option ng-repeat="country in cc_data" value="{{country.id}}" >{{country.text}}</option> </select> <span class="help-inline">select only relays from these countries</span> <span class="help-inline">select only relays from this country</span> </div> </div> <label class="control-label" for="exits">Exits</label> <div class="controls"> <label class="radio"> <input type="radio" class="exits" name="exits" id="all_relays" value="all_relays" ng-model='query.exit_filter' checked> All relay </label> <label class="radio"> <input type="radio" class="exits" name="exits" id="fast_exits_only" value="fast_exits_only" ng-model='query.exit_filter'> Fast exit relays (95+ Mbit/s, 5000+ KB/s, 80/443/554/1755, 2 relays per /24) </label> <label class="radio"> <input type="radio" class="exits" name="exits" id="almost_fast_exits_only" value="almost_fast_exits_only" ng-model="almost_fast_exits_only"> Almost fast exit relays (80+ Mbit/s, 2000+ KB/s, 80/443, not in set of fast exits) </label> <label class="radio"> <input type="radio" class="exits" name="exits" id="fast_exits_only_any_network" ng-model="query.exit_filter" value="fast_exits_only_any_network"> Fast exits relays any network (95+ Mbit/s, 5000+ KB/s, 80/443/554/1755) </label> </div> <div class="control-group"> <h3> Group </h3> <label class="control-label" for="country">Country</label> Loading @@ -158,8 +131,8 @@ </div> <label class="control-label" for="as">AS</label> <div class="controls"> <input type="checkbox" id="by_as" value="True" name="by_as" ng-model="query.by_as"> group relays by AS </label> <label class="checkbox"> <input type="checkbox" id="by_as" value="True" name="by_as" ng-model="query.by_as"> group relays by AS</label> </div> </div> Loading @@ -168,8 +141,8 @@ <label class="control-label" for="top">Number of results</label> <div class="controls"> <input type="text" class="input-xlarge" id="top" name="top" placeholder="10" value="10" ng-model="query.top"> <span class="help-inline">display only the top results (-1 for all)</span> placeholder="-1" value="-1" ng-model="query.top" disabled="disabled"> <span class="help-inline">limiting of results is disabled</span> </div> </div> <div class="form-actions"> Loading @@ -180,111 +153,6 @@ </form> </div> <div class="hero-unit" ng-show="state == 'loading'" > <div class='loading'><img src="static/img/loader.gif" /></div> </div> <div class="hero-unit" ng-show="state == 'result_empty'"> <p>No results found</p> </div> <div id='result_table' class="hero-unit" ng-show="state == 'loaded' || state == 'sorting'"> <table class="table table-striped"> <thead> <tr> <th >#</th> <th sortable='ajax_sort' ui-jq='tooltip' sort_by='cw' invert='true' class='spinner-small' icon="static/img/ajax-loader.gif" title="Relative bandwidth weight assigned to this relay by the directory authorities"> Consensus Weights </th> <th sortable='ajax_sort' ui-jq='tooltip' sort_by='adv_bw' invert='true' class='spinner-small' icon="static/img/ajax-loader.gif" title="Relative advertised bandwidth of this relay compared to the total advertised bandwidth in the network">Advertised Bandwidth</th> <th sortable='ajax_sort' ui-jq='tooltip' sort_by='p_guard' invert=true icon="static/img/ajax-loader.gif" class='spinner-small' title=" Probability of this relay to be selected for the guard position">Guard Probability</th> <th sortable='ajax_sort' ui-jq='tooltip' sort_by='p_middle' invert=true icon="static/img/ajax-loader.gif" class='spinner-small' title="Probability of this relay to be selected for the middle position"> Middle Probability</th > <th sortable='ajax_sort' ui-jq='tooltip' sort_by='p_exit' invert=true icon="static/img/ajax-loader.gif" class='spinner-small' title="Probability of this relay to be selected for the exit position" > Exit Probability</th > <th sortable='ajax_sort' sort_by='nick' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Nickname</th> <th sortable='ajax_sort' sort_by='fp' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Fingerprint</th> <th sortable='ajax_sort' sort_by='exit' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Exit</th> <th sortable='ajax_sort' sort_by='guard' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Guard</th> <th sortable='ajax_sort' sort_by='cc' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Country</th> <th sortable='ajax_sort' sort_by='as_info' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Autonomous System</th> </tr> </thead> <tfoot> <tr ng-show="data.excluded"> <td> {{ data.excluded.index }} </td> <td> {{ data.excluded.cw | number:4 }}%</td> <td> {{ data.excluded.adv_bw | number:4}}%</td> <td>{{ data.excluded.p_guard | number:4 }}%</td> <td>{{ data.excluded.p_middle | number:4 }}%</td> <td>{{ data.excluded.p_exit | number:4 }}%</td> <td id="extra_table_title">{{ data.excluded.nick }}</td> <td> {{data.excluded.fp }} </td> <td>{{ data.excluded.exit }}</td> <td>{{ data.excluded.guard }}</td> <td>{{ data.excluded.cc }}</td> <td>{{ data.excluded.as_info }}</td> </tr> <tr ng-show="data.total"> <td> {{ data.total.index }} </td> <td> {{ data.total.cw | number:4 }}%</td> <td> {{ data.total.adv_bw | number:4}}%</td> <td>{{ data.total.p_guard | number:4 }}%</td> <td>{{ data.total.p_middle | number:4 }}%</td> <td>{{ data.total.p_exit | number:4 }}%</td> <td id='extra_table_title'>{{ data.total.nick }}</td> <td> {{data.total.fp }} </td> <td>{{ data.total.exit }}</td> <td>{{ data.total.guard }}</td> <td>{{ data.total.cc }}</td> <td>{{ data.total.as_info }}</td> </tr> </tfoot> <tbody> <tr ng-repeat="relay in data.results "> <td> {{ relay.index }} </td> <td> {{ relay.cw | number:4 }}%</td> <td> {{ relay.adv_bw | number:4}}%</td> <td>{{ relay.p_guard | number:4 }}%</td> <td>{{ relay.p_middle | number:4 }}%</td> <td>{{ relay.p_exit | number:4 }}%</td> <td>{{ relay.nick }}</td> <td> <span ng-show="relay.link"> <a href="https://atlas.torproject.org/#details/{{relay.fp}}" >{{relay.fp | truncate:8:30}}</a> </span> <span ng-show="!relay.link">{{relay.fp | truncate:8:30}}</span> </td> <td>{{ relay.exit }}</td> <td>{{ relay.guard }}</td> <td>{{ relay.cc }}</td> <td>{{ relay.as_info }}</td> <tr> </tbody> </table> </div> </div> </div> <!-- /container --> <!-- Le javascript Loading @@ -300,5 +168,22 @@ <script src="static/js/directives.js"></script> <script src="static/js/filters.js"></script> <script src="static/js/angularize.js"></script> <script type="text/javascript"> /* Onionoo does not yet support multiple flags */ $('#guards_only').on('change', function(){ if ($(this).is(':checked')) { $('#exits_only').attr('disabled', 'disabled'); } else { $('#exits_only').removeAttr('disabled', 'disabled'); } }); $('#exits_only').on('change', function(){ if ($(this).is(':checked')) { $('#guards_only').attr('disabled', 'disabled'); } else { $('#guards_only').removeAttr('disabled', 'disabled'); } }); </script> </body> </html> Loading
app.py +1 −57 Original line number Diff line number Diff line Loading @@ -123,63 +123,7 @@ def index(): @app.route('/result.json', methods=['GET']) def json_result(): options = Opt(dict(request.args.items())) if "TESTING_DATAFILE" in app.config and "TESTING" in app.config: stats = compass.RelayStats(options,app.config['TESTING_DATAFILE']) else: stats = compass.RelayStats(options) results = stats.select_relays(stats.relays, options) relays = stats.sort_and_reduce(results, options) return Response(json.dumps(relays, cls=ResultEncoder), mimetype='application/json') @app.route('/result', methods=['GET']) def result(): options = Opt() sort_key = None relays = [] for key, value in request.args.items(): if key == "top": try: options.top = int(value) except: options.top = -1 elif key == "sort": sort_key = value elif key in ["country", "ases"]: if value: setattr(options, key, [value]) else: setattr(options, key, None) elif key == "exits": setattr(options, value, True) else: setattr(options, key, value) stats = compass.RelayStats(options) sorted_groups = stats.format_and_sort_groups(stats.relays, by_country=options.by_country, by_as_number=options.by_as, links=options.links) output_string = stats.print_groups(sorted_groups, options.top, by_country=options.by_country, by_as_number=options.by_as, short=None, links=None) results = parse(output_string, options.by_country or options.by_as, sort_key) if sort_key: for key in sorted(results.iterkeys(), reverse=True): for value in results[key]: relays.append(value) else: relays = results return render_template('result.html', results=relays, grouping=options.by_as or options.by_country) return jsonify({"error": "The Compass service has been partially shut down. See https://trac.torproject.org/projects/tor/ticket/24445."}) if __name__ == '__main__': # Bind to PORT if defined, otherwise default to 5000. Loading
static/js/angularize.js +35 −51 Original line number Diff line number Diff line Loading @@ -11,11 +11,6 @@ compassModule.controller('CompassCtrl',function CompassCtrl($scope,$http,$locati $scope.state = "hidden" $scope.query = { exit_filter:"all_relays", links:true, sort:'cw', sort_reverse: true, country: null } /** Watch the location bar to allow us to load saved searches **/ Loading @@ -26,59 +21,48 @@ compassModule.controller('CompassCtrl',function CompassCtrl($scope,$http,$locati } }) /** Make a sorting request /** Make a data request from the form * * Call 'success_cb' if the request is successful */ $scope.ajax_sort = function(sortBy, invert, success_cb) { $scope.query.sort = sortBy $scope.query.sort_reverse = invert //Update the location bar to track sorting $location.search($scope.query) $http.get('result.json',{"params":$scope.query}) .success(function(data) { if (data.results.length > 0) { $scope.data = data $scope.request = function(success_cb) { var rs_query = ""; if (success_cb !== null){ success_cb() if ((typeof $scope.query["country"]) !== "undefined" && $scope.query["country"] !== "") { rs_query += "country:" + $scope.query["country"] + " "; } $('body').animate({scrollTop:$("div#result_table").offset().top},500) if ((typeof $scope.query["ases"]) !== "undefined" && $scope.query["ases"] !== "") { rs_query += "as:" + $scope.query["ases"] + " "; } else { $scope.state = "result_empty" if ((typeof $scope.query["family"]) !== "undefined" && $scope.query["family"] !== "") { rs_query += "family:" + $scope.query["family"] + " "; } }) if ((typeof $scope.query["exits_only"]) !== "undefined" && $scope.query["exits_only"] == true) { rs_query += "flag:exit" + " "; } else if ((typeof $scope.query["guards_only"]) !== "undefined" && $scope.query["guards_only"] == true) { rs_query += "flag:guard" + " "; } /** Make a data request from the form * * Call 'success_cb' if the request is successful */ $scope.request = function(success_cb) { $scope.state = 'loading' var by_country = ((typeof $scope.query["by_country"]) !== "undefined" && $scope.query["by_country"] == true); var by_as = ((typeof $scope.query["by_as"]) !== "undefined" && $scope.query["by_as"] == true); //Set the location bar for this search $location.search($scope.query) var rs_url = "https://atlas.torproject.org/"; $http.get('result.json',{"params":$scope.query}) .success(function(data) { if (data.results.length > 0) { $scope.data = data $scope.state = "loaded" if (success_cb != null){ success_cb() if (!by_country) { if (!by_as) { rs_url += "#search/running:true " + rs_query.trim(); } else { rs_url += "#aggregate/as/" + rs_query.trim(); } $('body').animate({scrollTop:$("div#result_table").offset().top},500) } else { if (!by_as) { rs_url += "#aggregate/cc/" + rs_query.trim(); } else { rs_url += "#aggregate/ascc/" + rs_query.trim(); } else { $scope.state = "result_empty" } }) document.location = rs_url; }; $scope.reset = function() { Loading
templates/index.html +29 −144 Original line number Diff line number Diff line Loading @@ -68,28 +68,24 @@ <div class="container" ng-controller="CompassCtrl"> <div class="hero-unit"> <div class="alert alert-danger"> <p>The Tor Metrics team plans to shut down the Compass service at the end of December 2017. Aggregated search functionality has been <p>The Compass service has now been partially shut down. Aggregated search functionality has been integrated into <a href="https://atlas.torproject.org/#aggregate">Relay Search</a> (formerly known as Atlas) to give a unified tool for exploring both single relays and aggregations of relays.<p> exploring both single relays and aggregations of relays. Any queries made will redirect to Relay Search to display results.<p> <p>Please ensure that all the functionality you require is available in Relay Search before Compass is shut down. If any functionality is missing, please <a href="https://trac.torproject.org/projects/tor/newticket?component=Metrics/Atlas&parent=%2324445">file a ticket to request that it be added</a>.</p> <p>This search form will no longer be available from 15th January 2018.</p> </div> <form class="form-horizontal" id="form"> <fieldset> <legend>Compass</legend> <div class="control-group"> <h3> Filter </h3> <label class="control-label" for="inactive">Inactive</label> <div class="controls"> <label class="checkbox"> <input type="checkbox" id="inactive" value="True" name="inactive" ng-model='query.inactive'> include relays in selection that aren't currently running </label> </div> <label class="control-label" for="guards">Guards</label> <div class="controls"> <label class="checkbox"> Loading Loading @@ -118,36 +114,13 @@ <label class="control-label" for="cc">Country</label> <div class="controls"> <select id="country" name="country" ng-model='query.country' ui-select2 multiple data-placeholder="Germany"> ui-select2 data-placeholder="Germany"> <option value="">Any</option> <option ng-repeat="country in cc_data" value="{{country.id}}" >{{country.text}}</option> </select> <span class="help-inline">select only relays from these countries</span> <span class="help-inline">select only relays from this country</span> </div> </div> <label class="control-label" for="exits">Exits</label> <div class="controls"> <label class="radio"> <input type="radio" class="exits" name="exits" id="all_relays" value="all_relays" ng-model='query.exit_filter' checked> All relay </label> <label class="radio"> <input type="radio" class="exits" name="exits" id="fast_exits_only" value="fast_exits_only" ng-model='query.exit_filter'> Fast exit relays (95+ Mbit/s, 5000+ KB/s, 80/443/554/1755, 2 relays per /24) </label> <label class="radio"> <input type="radio" class="exits" name="exits" id="almost_fast_exits_only" value="almost_fast_exits_only" ng-model="almost_fast_exits_only"> Almost fast exit relays (80+ Mbit/s, 2000+ KB/s, 80/443, not in set of fast exits) </label> <label class="radio"> <input type="radio" class="exits" name="exits" id="fast_exits_only_any_network" ng-model="query.exit_filter" value="fast_exits_only_any_network"> Fast exits relays any network (95+ Mbit/s, 5000+ KB/s, 80/443/554/1755) </label> </div> <div class="control-group"> <h3> Group </h3> <label class="control-label" for="country">Country</label> Loading @@ -158,8 +131,8 @@ </div> <label class="control-label" for="as">AS</label> <div class="controls"> <input type="checkbox" id="by_as" value="True" name="by_as" ng-model="query.by_as"> group relays by AS </label> <label class="checkbox"> <input type="checkbox" id="by_as" value="True" name="by_as" ng-model="query.by_as"> group relays by AS</label> </div> </div> Loading @@ -168,8 +141,8 @@ <label class="control-label" for="top">Number of results</label> <div class="controls"> <input type="text" class="input-xlarge" id="top" name="top" placeholder="10" value="10" ng-model="query.top"> <span class="help-inline">display only the top results (-1 for all)</span> placeholder="-1" value="-1" ng-model="query.top" disabled="disabled"> <span class="help-inline">limiting of results is disabled</span> </div> </div> <div class="form-actions"> Loading @@ -180,111 +153,6 @@ </form> </div> <div class="hero-unit" ng-show="state == 'loading'" > <div class='loading'><img src="static/img/loader.gif" /></div> </div> <div class="hero-unit" ng-show="state == 'result_empty'"> <p>No results found</p> </div> <div id='result_table' class="hero-unit" ng-show="state == 'loaded' || state == 'sorting'"> <table class="table table-striped"> <thead> <tr> <th >#</th> <th sortable='ajax_sort' ui-jq='tooltip' sort_by='cw' invert='true' class='spinner-small' icon="static/img/ajax-loader.gif" title="Relative bandwidth weight assigned to this relay by the directory authorities"> Consensus Weights </th> <th sortable='ajax_sort' ui-jq='tooltip' sort_by='adv_bw' invert='true' class='spinner-small' icon="static/img/ajax-loader.gif" title="Relative advertised bandwidth of this relay compared to the total advertised bandwidth in the network">Advertised Bandwidth</th> <th sortable='ajax_sort' ui-jq='tooltip' sort_by='p_guard' invert=true icon="static/img/ajax-loader.gif" class='spinner-small' title=" Probability of this relay to be selected for the guard position">Guard Probability</th> <th sortable='ajax_sort' ui-jq='tooltip' sort_by='p_middle' invert=true icon="static/img/ajax-loader.gif" class='spinner-small' title="Probability of this relay to be selected for the middle position"> Middle Probability</th > <th sortable='ajax_sort' ui-jq='tooltip' sort_by='p_exit' invert=true icon="static/img/ajax-loader.gif" class='spinner-small' title="Probability of this relay to be selected for the exit position" > Exit Probability</th > <th sortable='ajax_sort' sort_by='nick' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Nickname</th> <th sortable='ajax_sort' sort_by='fp' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Fingerprint</th> <th sortable='ajax_sort' sort_by='exit' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Exit</th> <th sortable='ajax_sort' sort_by='guard' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Guard</th> <th sortable='ajax_sort' sort_by='cc' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Country</th> <th sortable='ajax_sort' sort_by='as_info' invert=false icon="static/img/ajax-loader.gif" class='spinner-small' >Autonomous System</th> </tr> </thead> <tfoot> <tr ng-show="data.excluded"> <td> {{ data.excluded.index }} </td> <td> {{ data.excluded.cw | number:4 }}%</td> <td> {{ data.excluded.adv_bw | number:4}}%</td> <td>{{ data.excluded.p_guard | number:4 }}%</td> <td>{{ data.excluded.p_middle | number:4 }}%</td> <td>{{ data.excluded.p_exit | number:4 }}%</td> <td id="extra_table_title">{{ data.excluded.nick }}</td> <td> {{data.excluded.fp }} </td> <td>{{ data.excluded.exit }}</td> <td>{{ data.excluded.guard }}</td> <td>{{ data.excluded.cc }}</td> <td>{{ data.excluded.as_info }}</td> </tr> <tr ng-show="data.total"> <td> {{ data.total.index }} </td> <td> {{ data.total.cw | number:4 }}%</td> <td> {{ data.total.adv_bw | number:4}}%</td> <td>{{ data.total.p_guard | number:4 }}%</td> <td>{{ data.total.p_middle | number:4 }}%</td> <td>{{ data.total.p_exit | number:4 }}%</td> <td id='extra_table_title'>{{ data.total.nick }}</td> <td> {{data.total.fp }} </td> <td>{{ data.total.exit }}</td> <td>{{ data.total.guard }}</td> <td>{{ data.total.cc }}</td> <td>{{ data.total.as_info }}</td> </tr> </tfoot> <tbody> <tr ng-repeat="relay in data.results "> <td> {{ relay.index }} </td> <td> {{ relay.cw | number:4 }}%</td> <td> {{ relay.adv_bw | number:4}}%</td> <td>{{ relay.p_guard | number:4 }}%</td> <td>{{ relay.p_middle | number:4 }}%</td> <td>{{ relay.p_exit | number:4 }}%</td> <td>{{ relay.nick }}</td> <td> <span ng-show="relay.link"> <a href="https://atlas.torproject.org/#details/{{relay.fp}}" >{{relay.fp | truncate:8:30}}</a> </span> <span ng-show="!relay.link">{{relay.fp | truncate:8:30}}</span> </td> <td>{{ relay.exit }}</td> <td>{{ relay.guard }}</td> <td>{{ relay.cc }}</td> <td>{{ relay.as_info }}</td> <tr> </tbody> </table> </div> </div> </div> <!-- /container --> <!-- Le javascript Loading @@ -300,5 +168,22 @@ <script src="static/js/directives.js"></script> <script src="static/js/filters.js"></script> <script src="static/js/angularize.js"></script> <script type="text/javascript"> /* Onionoo does not yet support multiple flags */ $('#guards_only').on('change', function(){ if ($(this).is(':checked')) { $('#exits_only').attr('disabled', 'disabled'); } else { $('#exits_only').removeAttr('disabled', 'disabled'); } }); $('#exits_only').on('change', function(){ if ($(this).is(':checked')) { $('#guards_only').attr('disabled', 'disabled'); } else { $('#guards_only').removeAttr('disabled', 'disabled'); } }); </script> </body> </html>