public ReadController() {

    // start read handler processing
    Thread read_processor_thread =
        new AEThread("ReadController:ReadProcessor") {
          public void runSupport() {
            readProcessorLoop();
          }
        };
    read_processor_thread.setDaemon(true);
    read_processor_thread.setPriority(Thread.MAX_PRIORITY - 1);
    read_processor_thread.start();

    Set types = new HashSet();

    types.add(AzureusCoreStats.ST_NET_READ_CONTROL_LOOP_COUNT);
    types.add(AzureusCoreStats.ST_NET_READ_CONTROL_NP_COUNT);
    types.add(AzureusCoreStats.ST_NET_READ_CONTROL_P_COUNT);
    types.add(AzureusCoreStats.ST_NET_READ_CONTROL_WAIT_COUNT);
    types.add(AzureusCoreStats.ST_NET_READ_CONTROL_ENTITY_COUNT);
    types.add(AzureusCoreStats.ST_NET_READ_CONTROL_CON_COUNT);
    types.add(AzureusCoreStats.ST_NET_READ_CONTROL_READY_CON_COUNT);

    AzureusCoreStats.registerProvider(types, this);

    AEDiagnostics.addEvidenceGenerator(
        new AEDiagnosticsEvidenceGenerator() {
          public void generate(IndentWriter writer) {
            writer.println("Read Controller");

            try {
              writer.indent();

              ArrayList<RateControlledEntity> ref = normal_priority_entities;

              writer.println("normal - " + ref.size());

              for (int i = 0; i < ref.size(); i++) {

                RateControlledEntity entity = ref.get(i);

                writer.println(entity.getString());
              }

              ref = high_priority_entities;

              writer.println("priority - " + ref.size());

              for (int i = 0; i < ref.size(); i++) {

                RateControlledEntity entity = ref.get(i);

                writer.println(entity.getString());
              }
            } finally {

              writer.exdent();
            }
          }
        });
  }
  static {
    Set types = new HashSet();

    types.add(AzureusCoreStats.ST_TRACKER_READ_BYTES);
    types.add(AzureusCoreStats.ST_TRACKER_WRITE_BYTES);
    types.add(AzureusCoreStats.ST_TRACKER_ANNOUNCE_COUNT);
    types.add(AzureusCoreStats.ST_TRACKER_ANNOUNCE_TIME);
    types.add(AzureusCoreStats.ST_TRACKER_SCRAPE_COUNT);
    types.add(AzureusCoreStats.ST_TRACKER_SCRAPE_TIME);

    AzureusCoreStats.registerProvider(
        types,
        new AzureusCoreStatsProvider() {
          public void updateStats(Set types, Map values) {
            long read_bytes = 0;
            long write_bytes = 0;
            long announce_count = 0;
            long announce_time = 0;
            long scrape_count = 0;
            long scrape_time = 0;

            Iterator it = servers.iterator();

            while (it.hasNext()) {

              TRTrackerServerStats stats = ((TRTrackerServer) it.next()).getStats();

              read_bytes += stats.getBytesIn();
              write_bytes += stats.getBytesOut();
              announce_count += stats.getAnnounceCount();
              announce_time += stats.getAnnounceTime();
              scrape_count += stats.getScrapeCount();
              scrape_time += stats.getScrapeTime();
            }

            if (types.contains(AzureusCoreStats.ST_TRACKER_READ_BYTES)) {

              values.put(AzureusCoreStats.ST_TRACKER_READ_BYTES, new Long(read_bytes));
            }
            if (types.contains(AzureusCoreStats.ST_TRACKER_WRITE_BYTES)) {

              values.put(AzureusCoreStats.ST_TRACKER_WRITE_BYTES, new Long(write_bytes));
            }
            if (types.contains(AzureusCoreStats.ST_TRACKER_ANNOUNCE_COUNT)) {

              values.put(AzureusCoreStats.ST_TRACKER_ANNOUNCE_COUNT, new Long(announce_count));
            }
            if (types.contains(AzureusCoreStats.ST_TRACKER_ANNOUNCE_TIME)) {

              values.put(AzureusCoreStats.ST_TRACKER_ANNOUNCE_TIME, new Long(announce_time));
            }
            if (types.contains(AzureusCoreStats.ST_TRACKER_SCRAPE_COUNT)) {

              values.put(AzureusCoreStats.ST_TRACKER_SCRAPE_COUNT, new Long(scrape_count));
            }
            if (types.contains(AzureusCoreStats.ST_TRACKER_SCRAPE_TIME)) {

              values.put(AzureusCoreStats.ST_TRACKER_SCRAPE_TIME, new Long(scrape_time));
            }
          }
        });
  }