[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

[tor-commits] [metrics-web/master] Add news from a news.json file.



commit 182d61448b7f6ba32b3cccc68d3a0ecda45fea94
Author: Karsten Loesing <karsten.loesing@xxxxxxx>
Date:   Tue Dec 13 14:03:22 2016 +0100

    Add news from a news.json file.
---
 website/build.xml                                  |   3 +
 website/etc/news.json                              | 398 +++++++++++++++++++++
 .../torproject/metrics/web/ContentProvider.java    |  37 +-
 .../org/torproject/metrics/web/MetricServlet.java  |   4 +-
 website/src/org/torproject/metrics/web/News.java   |  44 +++
 .../org/torproject/metrics/web/NewsServlet.java    |  98 ++++-
 .../metrics/web/graphs/GraphParameterChecker.java  |   4 +-
 .../metrics/web/graphs/RObjectGenerator.java       |   4 +-
 .../metrics/web/graphs/TableParameterChecker.java  |   4 +-
 website/web/WEB-INF/news.jsp                       |   7 +
 10 files changed, 583 insertions(+), 20 deletions(-)

diff --git a/website/build.xml b/website/build.xml
index 6e156b4..c3aca68 100644
--- a/website/build.xml
+++ b/website/build.xml
@@ -54,6 +54,9 @@
       <zipfileset dir="etc"
                   prefix="WEB-INF/classes"
                   includes="categories.json"/>
+      <zipfileset dir="etc"
+                  prefix="WEB-INF/classes"
+                  includes="news.json"/>
       <metainf dir="etc"
                includes="context.xml"/>
     </war>
diff --git a/website/etc/news.json b/website/etc/news.json
new file mode 100644
index 0000000..66db558
--- /dev/null
+++ b/website/etc/news.json
@@ -0,0 +1,398 @@
+[
+  {
+    "start": "2012-05-15",
+    "end": "2012-12-15",
+    "place": "et",
+    "protocols": [
+      "&lt;OR&gt;"
+    ],
+    "description": "Ethiopia blocks Tor TLS.",
+    "links": [
+      "<a href=\"https://bugs.torproject.org/6045\";>ticket</a>",
+      "<a href=\"https://blog.torproject.org/blog/ethiopia-introduces-deep-packet-inspection\";>blog post 1</a>",
+      "<a href=\"https://blog.torproject.org/blog/update-censorship-ethiopia\";>blog post 2</a>"
+    ]
+  },
+  {
+    "start": "2013-08-19",
+    "end": "2014-04-28",
+    "protocols": [
+      "&lt;OR&gt;",
+      "relay"
+    ],
+    "description": "Relay users increase globally from about 800K to over 5M, when computers in the [https://en.wikipedia.org/wiki/Mevade_Botnet Mevade/Sefnit botnetbegan using Tor to communicate. The user count decreased in the following months through efforts to clean up the botnet. Sometime in 2014-04, the botnet switched from using Tor to using SSH.",
+    "links": [
+      "<a href=\"https://blog.torproject.org/blog/how-to-handle-millions-new-tor-clients\";>blog post</a>",
+      "<a href=\"https://research.torproject.org/techreports/botnet-tr-2013-11-20.pdf\";>tech report</a>",
+      "<a href=\"https://blog.fox-it.com/2013/09/05/large-botnet-cause-of-recent-tor-network-overload/\";>analysis</a>",
+      "<a href=\"https://www.facebook.com/notes/protect-the-graph/sefnit-is-back/1448087102098103\";>switch to SSH</a>"
+    ]
+  },
+  {
+    "start": "2013-10-27",
+    "protocols": [
+      "&lt;OR&gt;",
+      "relay"
+    ],
+    "description": "Microsoft adds the Mevade/Sefnit botnet signature to various security scanners.",
+    "links": [
+      "<a href=\"https://blogs.technet.microsoft.com/mmpc/2014/01/09/tackling-the-sefnit-botnet-tor-hazard/\";>blog post</a>"
+    ]
+  },
+  {
+    "start": "2013-11-03",
+    "protocols": [
+      "&lt;OR&gt;",
+      "relay"
+    ],
+    "description": "Microsoft adds the Mevade/Sefnit botnet signature to their Malicious Software Removal Tool.",
+    "links": [
+      "<a href=\"https://blogs.technet.microsoft.com/mmpc/2014/01/09/tackling-the-sefnit-botnet-tor-hazard/\";>blog post</a>"
+    ]
+  },
+  {
+    "start": "2015-11-18",
+    "end": "2015-12-10",
+    "place": "bd",
+    "protocols": [
+      "&lt;OR&gt;",
+      "obfs3",
+      "obfs4"
+    ],
+    "description": "Bangladesh blocks Facebook, WhatsApp, and Viber.",
+    "links": [
+      "<a href=\"http://phys.org/news/2015-12-bangladesh-facebook.html\";>news article</a>",
+      "<a href=\"https://archive.fo/fc2WQ\";>(archive)</a>",
+      "<a href=\"https://metrics.torproject.org/userstats-relay-country.html?start=2015-08-01&end=2016-02-01&country=bd&events=off\";>relay graph</a>"
+    ]
+  },
+  {
+    "start": "2016-04-28",
+    "protocols": [
+      "fte"
+    ],
+    "description": "Tor Browser 6.0a5 and 6.0a5-hardened released, which lack the fte pluggable transport on Mac.",
+    "links": [
+      "<a href=\"https://blog.torproject.org/blog/tor-browser-60a5-released\";>6.0a5 blog post</a>",
+      "<a href=\"https://blog.torproject.org/blog/tor-browser-60a5-hardened-released\";>6.0a5 blog post</a>",
+      "<a href=\"https://bugs.torproject.org/18495\";>ticket</a>"
+    ]
+  },
+  {
+    "start": "2016-05-30",
+    "protocols": [
+      "fte"
+    ],
+    "description": "Tor Browser 6.0 released, which lacks the fte pluggable transport on Mac.",
+    "links": [
+      "<a href=\"https://blog.torproject.org/blog/tor-browser-60-released\";>6.0 blog post</a>",
+      "<a href=\"https://bugs.torproject.org/18495\";>ticket</a>"
+    ]
+  },
+  {
+    "start": "2016-05-02",
+    "end": "2016-05-03",
+    "place": "br",
+    "protocols": [
+      "&lt;OR&gt;"
+    ],
+    "description": "WhatsApp block in Brazil",
+    "links": [
+      "<a href=\"https://blog.torproject.org/blog/tracking-impact-whatsapp-blockage-tor\";>blog post</a>",
+      "<a href=\"https://ooni.torproject.org/post/brazil-whatsapp-block/\";>OONI report</a>",
+      "<a href=\"http://bloqueios.info/en/casos/block-for-non-compliance-with-judicial-requests-for-user-data-3/\";>bloqueios report</a>"
+    ]
+  },
+  {
+    "start": "2016-06-01",
+    "place": "kz",
+    "protocols": [
+      "&lt;OR&gt;"
+    ],
+    "description": "Kazakhstan blocks vanilla Tor TLS. Users mostly switch to obfs4.",
+    "links": [
+      "<a href=\"https://bugs.torproject.org/20348\";>ticket</a>"
+    ]
+  },
+  {
+    "start": "2016-08-20",
+    "place": "ir",
+    "protocols": [
+      "&lt;OR&gt;"
+    ],
+    "description": "Iran somehow blocks most direct Tor connections. May also affect bridge users, but it's hard to tell because there were few vanilla bridge users anyway.",
+    "links": [
+      "<a href=\"https://bugs.torproject.org/20216\";>ticket</a>"
+    ]
+  },
+  {
+    "start": "2016-08-24",
+    "protocols": [
+      "bridge"
+    ],
+    "description": "tor 0.2.8.7 and 0.2.9.2-alpha are released, changing the bridge authority from Tonga to Bifroest.",
+    "links": [
+      "<a href=\"https://blog.torproject.org/blog/tor-0287-released-important-fixes\";>0.2.8.7 announcement</a>"
+    ]
+  },
+  {
+    "start": "2016-08-31",
+    "protocols": [
+      "bridge"
+    ],
+    "description": "CollecTor begins publishing bridge stats from the new bridge authority Bifroest.",
+    "links": [
+      "<a href=\"https://lists.torproject.org/pipermail/tor-dev/2016-August/011336.html\";>post</a>"
+    ]
+  },
+  {
+    "start": "2016-09-02",
+    "protocols": [
+      "bridge"
+    ],
+    "description": "The former bridge authority Tonga shuts down. Bridges that have not updated to tor 0.2.8.7 or 0.2.9.2-alpha (which include all 5 default obfs3 bridges and 3/16 default obfs4 bridges) stop reporting statistics.",
+    "links": [
+      "<a href=\"https://trac.torproject.org/projects/tor/ticket/19690#comment:17\";>shutdown notice</a>",
+      "<a href=\"https://blog.torproject.org/blog/new-bridge-authority\";>blog post</a>",
+      "<a href=\"https://metrics.torproject.org/networksize.html?start=2016-07-01&end=2016-09-23\";>loss of reporting bridges</a>"
+    ]
+  },
+  {
+    "start": "2016-09-04",
+    "place": "ir",
+    "protocols": [
+      "&lt;OR&gt;"
+    ],
+    "description": "Iran intensifies the blocking begun on 2016-08-20, getting most of the remaining direct users. There is interference in the graphs from the bridge authority changeover on 2016-09-02, but because the changeover would not have affected counts of ''direct'' users, it may be a coincidence.",
+    "links": [
+      "<a href=\"https://bugs.torproject.org/20216\";>ticket</a>"
+    ]
+  },
+  {
+    "start": "2016-09-20",
+    "protocols": [
+      "meek"
+    ],
+    "description": "macOS 10.12 (Sierra) is released, breaking some programs that are built with Go <1.7, including the meek-client that comes with Tor Browser. (See 2016-11-15 unbreaking event.)",
+    "links": [
+      "<a href=\"https://bugs.torproject.org/20250\";>ticket</a>"
+    ]
+  },
+  {
+    "start": "2016-09-23",
+    "protocols": [
+      "obfs3"
+    ],
+    "description": "Default obfs3 bridges ndnop0 and ndnop2 upgrade and begin reporting statistics to the new bridge authority Bifroest.",
+    "links": [
+      "<a href=\"https://lists.torproject.org/pipermail/metrics-team/2016-September/000217.html\";>post on bridges not reporting statistics</a>"
+    ]
+  },
+  {
+    "start": "2016-09-23",
+    "protocols": [
+      "obfs4"
+    ],
+    "description": "Default obfs3 bridges ndnop3 and ndnop5 upgrade and begin reporting statistics to the new bridge authority Bifroest.",
+    "links": [
+      "<a href=\"https://lists.torproject.org/pipermail/metrics-team/2016-September/000217.html\";>post on bridges not reporting statistics</a>"
+    ]
+  },
+  {
+    "start": "2016-09-23",
+    "protocols": [
+      "obfs3"
+    ],
+    "description": "Default obfs3 bridges \"Unnamed\" and \"Unnamed\" (fingerprint <a href=\"https://atlas.torproject.org/#details/AF9F66B7B04F8FF6F32D455F05135250A16543C9\";>AF9F66B7B04F8FF6F32D455F05135250A16543C9</a>) upgrade and begin reporting statistics to the new bridge authority Bifroest.",
+    "links": []
+  },
+  {
+    "start": "2016-09-24",
+    "protocols": [
+      "obfs3"
+    ],
+    "description": "Default obfs3 bridge LeifEricson upgrades and begins reporting statistics to the new bridge authority Bifroest. This is the last obfs3 bridge that hadn't upgraded.",
+    "links": []
+  },
+  {
+    "start": "2016-09-24",
+    "protocols": [
+      "obfs4"
+    ],
+    "description": "Default obfs4 bridge LeifEricson upgrades and begins reporting statistics to the new bridge authority Bifroest. This is the last obfs4 bridge that hadn't upgraded.",
+    "links": []
+  },
+  {
+    "start": "2016-10-02",
+    "end": "2016-10-03",
+    "place": "eg",
+    "protocols": [
+      "&lt;OR&gt;",
+      "relay"
+    ],
+    "description": "Reports that direct connections from Egypt are blocked; bridges are required. Maybe be the same as the block beginning 2016-10-25.",
+    "links": [
+      "<a href=\"https://ooni.torproject.org/post/egypt-network-interference/#attempts-to-block-tor\";>OONI report</a>"
+    ]
+  },
+  {
+    "start": "2016-10-08",
+    "end": "2016-10-09",
+    "place": "tr",
+    "description": "Turkey blocks storage services including Dropbox, Google Drive, OneDrive, and GitHub. Most (all?) of the blocks were rescinded the next day.",
+    "links": [
+      "<a href=\"https://turkeyblocks.org/2016/10/08/google-drive-dropbox-blocked-in-turkey/\";>blocking article</a>",
+      "<a href=\"https://twitter.com/TurkeyBlocks/status/785054084856512512\";>unblocking tweet</a>",
+      "<a href=\"https://www.turkishminute.com/2016/10/09/turkey-lifts-block-dropbox-google-drive-onedrive-remains-blocked/\";>unblocking article</a>"
+    ]
+  },
+  {
+    "start": "2016-10-19",
+    "end": "2016-11-10",
+    "protocols": [
+      "meek"
+    ],
+    "description": "Large decrease in meek users, perhaps caused by problems in Orbot 15.0.2 BETA 1 that were fixed in Orbot 15.2.0 RC8.",
+    "links": [
+      "<a href=\"https://bugs.torproject.org/20495\";>ticket</a>",
+      "<a href=\"https://lists.torproject.org/pipermail/tor-project/2016-October/000764.html\";>initial email</a>",
+      "<a href=\"https://lists.torproject.org/pipermail/tor-project/2016-November/000778.html\";>followup email</a>",
+      "<a href=\"https://groups.google.com/d/msg/traffic-obf/CSJLt3t-_OI/FnAqWqquAwAJ\";>Orbot mail</a>"
+    ]
+  },
+  {
+    "start": "2016-10-25",
+    "place": "eg",
+    "protocols": [
+      "&lt;OR&gt;",
+      "relay"
+    ],
+    "description": "Egypt blocks Tor directory authorities and public relays by TCP RST. Bridges work.",
+    "links": [
+      "<a href=\"https://ooni.torproject.org/post/egypt-network-interference/#attempts-to-block-tor\";>OONI report</a>"
+    ]
+  },
+  {
+    "start": "2016-11-03",
+    "place": "tr",
+    "description": "Turkey blocks Facebook, Twitter, YouTube, WhatsApp",
+    "links": [
+      "<a href=\"https://turkeyblocks.org/2016/11/04/social-media-shutdown-turkey/\";>article</a>"
+    ]
+  },
+  {
+    "start": "2016-11-04",
+    "place": "tr",
+    "description": "Turkey orders a block on VPN services and Tor",
+    "links": [
+      "<a href=\"http://turk-internet.com/portal/yazigoster.php?yaziid=54465\";>Turkish article</a>",
+      "<a href=\"https://motherboard.vice.com/read/turkey-doubles-down-on-censorship-with-block-on-vpns-tor\";>English article</a>"
+    ]
+  },
+  {
+    "start": "2016-11-15",
+    "protocols": [
+      "meek"
+    ],
+    "description": "Tor Browser 6.0.6 is released, unbreaking meek on macOS 10.12 (Sierra). (See 2016-09-20 breaking event.)",
+    "links": [
+      "<a href=\"https://blog.torproject.org/blog/tor-browser-606-released\";>blog post</a>",
+      "<a href=\"https://bugs.torproject.org/20250#comment:29\";>ticket</a>"
+    ]
+  },
+  {
+    "start": "2016-11-15",
+    "protocols": [
+      "obfs4"
+    ],
+    "description": "Default obfs4 bridges ndnop3 and ndnop5 turn on timing obfuscation (`iat-mode`).",
+    "links": [
+      "<a href=\"https://lists.torproject.org/pipermail/tor-project/2016-November/000780.html\";>mailing list post</a>",
+      "<a href=\"https://bugs.torproject.org/20837\";>ticket</a>"
+    ]
+  },
+  {
+    "start": "2016-11-18",
+    "protocols": [
+      "obfs4"
+    ],
+    "description": "Default obfs4 bridge <a href=\"https://atlas.torproject.org/#details/D9C805C955CB124D188C0D44F271E9BE57DE2109\";>Lisbeth</a> turns on timing obfuscation (`iat-mode=1`).",
+    "links": [
+      "<a href=\"https://bugs.torproject.org/20837\";>ticket</a>"
+    ]
+  },
+  {
+    "start": "2016-09-23",
+    "end": "2016-11-28",
+    "protocols": [
+      "obfs3"
+    ],
+    "description": "Outage of default obfs3 bridges \"Unnamed\" and \"Unnamed\" (fingerprint <a href=\"https://atlas.torproject.org/#details/AF9F66B7B04F8FF6F32D455F05135250A16543C9\";>AF9F66B7B04F8FF6F32D455F05135250A16543C9</a>). (Start date not known for sure, though it must have been after 2016-09-23; discussed in non-archived tor-team email.)",
+    "links": []
+  },
+  {
+    "start": "2016-12-01",
+    "place": "by",
+    "protocols": [
+      "&lt;OR&gt;",
+      "relay"
+    ],
+    "description": "Belarus blocks the addresses of public Tor relays, apparently by RST injection. Bridges work, even unobfuscated ones.",
+    "links": [
+      "<a href=\"https://bugs.torproject.org/20907\";>ticket</a>",
+      "<a href=\"https://geektimes.ru/post/283392/\";>article (Russian)</a>",
+      "<a href=\"https://ooni.torproject.org/post/belarus-fries-onion/\";>OONI blog post</a>"
+    ]
+  },
+  {
+    "start": "2016-02-24",
+    "place": "tm",
+    "protocols": [
+      "&lt;OR&gt;"
+    ],
+    "description": "Large drop in direct users in Turkmenistan",
+    "links": [
+      "<a href=\"https://metrics.torproject.org/userstats-relay-country.html?start=2015-11-01&end=2016-04-01&country=tm&events=off\";>graph</a>"
+    ],
+    "unknown": true
+  },
+  {
+    "start": "2016-08-24",
+    "place": "cn",
+    "protocols": [
+      "&lt;OR&gt;"
+    ],
+    "description": "Large decrease in users in China",
+    "links": [
+      "<a href=\"https://metrics.torproject.org/userstats-relay-country.html?start=2016-07-30&end=2016-10-28&country=cn&events=off\";>relay</a>",
+      "<a href=\"https://metrics.torproject.org/userstats-bridge-country.html?start=2016-07-30&end=2016-10-28&country=cn\";>bridge</a>"
+    ],
+    "unknown": true
+  },
+  {
+    "start": "2016-10-09",
+    "end": "2016-10-25",
+    "place": "il",
+    "protocols": [
+      "&lt;OR&gt;"
+    ],
+    "description": "Direct users fluctuate wildly in Israel. Bridge users not affected.",
+    "links": [
+      "<a href=\"https://metrics.torproject.org/userstats-relay-country.html?start=2016-07-28&end=2016-10-26&country=il&events=off\";>graph</a>"
+    ],
+    "unknown": true
+  },
+  {
+    "start": "2016-11-20",
+    "place": "sa",
+    "protocols": [
+      "&lt;OR&gt;",
+      "relay"
+    ],
+    "description": "Decrease in direct users in Saudi Arabia.",
+    "links": [
+      "<a href=\"https://bugs.torproject.org/20785\";>ticket</a>"
+    ],
+    "unknown": true
+  }
+]
diff --git a/website/src/org/torproject/metrics/web/ContentProvider.java b/website/src/org/torproject/metrics/web/ContentProvider.java
index 606e7db..2dd9105 100644
--- a/website/src/org/torproject/metrics/web/ContentProvider.java
+++ b/website/src/org/torproject/metrics/web/ContentProvider.java
@@ -6,33 +6,48 @@ package org.torproject.metrics.web;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
 
-import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
-public class MetricsProvider {
+public class ContentProvider {
 
-  private static MetricsProvider instance = new MetricsProvider();
+  private static ContentProvider instance = new ContentProvider();
 
-  public static MetricsProvider getInstance() {
-    return MetricsProvider.instance;
+  public static ContentProvider getInstance() {
+    return ContentProvider.instance;
   }
 
   private List<Metric> metricsList;
 
-  private MetricsProvider() {
-    InputStream in = this.getClass().getClassLoader()
-        .getResourceAsStream("metrics.json");
+  private List<Category> categoriesList;
+
+  private List<News> newsList;
+
+  private ContentProvider() {
     Gson gson = new GsonBuilder().create();
-    Metric[] metricsArray = gson.fromJson(new InputStreamReader(in),
-        Metric[].class);
-    this.metricsList = Arrays.asList(metricsArray);
+    this.metricsList = Arrays.asList(gson.fromJson(new InputStreamReader(
+        this.getClass().getClassLoader().getResourceAsStream("metrics.json")),
+        Metric[].class));
+    this.categoriesList = Arrays.asList(gson.fromJson(new InputStreamReader(
+        this.getClass().getClassLoader().getResourceAsStream(
+        "categories.json")), Category[].class));
+    this.newsList = Arrays.asList(gson.fromJson(new InputStreamReader(
+        this.getClass().getClassLoader().getResourceAsStream(
+        "news.json")), News[].class));
   }
 
   public List<Metric> getMetricsList() {
     return new ArrayList<Metric>(this.metricsList);
   }
+
+  public List<Category> getCategoriesList() {
+    return new ArrayList<Category>(this.categoriesList);
+  }
+
+  public List<News> getNewsList() {
+    return new ArrayList<News>(this.newsList);
+  }
 }
 
diff --git a/website/src/org/torproject/metrics/web/MetricServlet.java b/website/src/org/torproject/metrics/web/MetricServlet.java
index 8de6922..a280ee4 100644
--- a/website/src/org/torproject/metrics/web/MetricServlet.java
+++ b/website/src/org/torproject/metrics/web/MetricServlet.java
@@ -51,7 +51,7 @@ public abstract class MetricServlet extends HttpServlet {
 
   @Override
   public void init() throws ServletException {
-    this.metrics = MetricsProvider.getInstance().getMetricsList();
+    this.metrics = ContentProvider.getInstance().getMetricsList();
     Map<String, String> allTypesAndTitles = new HashMap<String, String>();
     Map<String, String[]> dataIds = new HashMap<String, String[]>();
     Map<String, String[]> relatedIds = new HashMap<String, String[]>();
@@ -116,7 +116,7 @@ public abstract class MetricServlet extends HttpServlet {
       }
     }
     for (Category category :
-        CategoriesProvider.getInstance().getCategoriesList()) {
+        ContentProvider.getInstance().getCategoriesList()) {
       for (String id : category.getMetrics()) {
         categories.put(id, category);
       }
diff --git a/website/src/org/torproject/metrics/web/News.java b/website/src/org/torproject/metrics/web/News.java
new file mode 100644
index 0000000..d16c3a1
--- /dev/null
+++ b/website/src/org/torproject/metrics/web/News.java
@@ -0,0 +1,44 @@
+/* Copyright 2016 The Tor Project
+ * See LICENSE for licensing information */
+
+package org.torproject.metrics.web;
+
+public class News {
+
+  private String start;
+
+  private String end;
+
+  private String place;
+
+  private String[] protocols;
+
+  private String description;
+
+  private String[] links;
+
+  String getStart() {
+    return start;
+  }
+
+  String getEnd() {
+    return end;
+  }
+
+  String getPlace() {
+    return place;
+  }
+
+  String[] getProtocols() {
+    return protocols;
+  }
+
+  String getDescription() {
+    return description;
+  }
+
+  String[] getLinks() {
+    return links;
+  }
+}
+
diff --git a/website/src/org/torproject/metrics/web/NewsServlet.java b/website/src/org/torproject/metrics/web/NewsServlet.java
index 5186dc6..f924b67 100644
--- a/website/src/org/torproject/metrics/web/NewsServlet.java
+++ b/website/src/org/torproject/metrics/web/NewsServlet.java
@@ -4,6 +4,18 @@
 package org.torproject.metrics.web;
 
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TimeZone;
+import java.util.TreeMap;
+import java.util.TreeSet;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
@@ -14,11 +26,95 @@ public class NewsServlet extends HttpServlet {
 
   private static final long serialVersionUID = -7696996243187241242L;
 
+  protected SortedSet<News> sortedNews;
+
+  @Override
+  public void init() throws ServletException {
+    SortedSet<News> sortedNews = new TreeSet<News>(new Comparator<News>() {
+      public int compare(News o1, News o2) {
+        return o1.getStart().compareTo(o2.getStart()) * -1;
+      }
+    });
+    for (News news : ContentProvider.getInstance().getNewsList()) {
+      if (news.getStart() != null) {
+        sortedNews.add(news);
+      }
+    }
+    this.sortedNews = sortedNews;
+  }
+
   @Override
   public void doGet(HttpServletRequest request,
       HttpServletResponse response) throws IOException, ServletException {
 
-    /* Forward the request to the JSP that does all the hard work. */
+    /* Create categories based on current system time. */
+    Map<String, String> cutOffDates = new LinkedHashMap<String, String>();
+    Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"), Locale.US);
+    cal.set(Calendar.DAY_OF_WEEK, 1);
+    cutOffDates.put(String.format("%tF", cal), "This week");
+    cal.set(Calendar.DAY_OF_MONTH, 1);
+    cutOffDates.put(String.format("%tF", cal), "This month");
+    cal.set(Calendar.MONTH, cal.get(Calendar.MONTH) /3 * 3);
+    cutOffDates.put(String.format("%tF", cal), "This quarter");
+    cal.set(Calendar.MONTH, 0);
+    String yearStart = String.format("%tF", cal);
+    cutOffDates.put(yearStart, "This year");
+    do {
+      cal.add(Calendar.YEAR, -1);
+      yearStart = String.format("%tF", cal);
+      cutOffDates.put(yearStart, String.format("%tY", cal));
+    } while (yearStart.compareTo(this.sortedNews.first().getStart()) > 0);
+
+    /* Sort news into categories. */
+    Map<String, List<String[]>> newsByCategory =
+        new LinkedHashMap<String, List<String[]>>();
+    for (String category : cutOffDates.values()) {
+      newsByCategory.put(category, new ArrayList<String[]>());
+    }
+    for (News news : this.sortedNews) {
+      StringBuilder sb = new StringBuilder();
+      sb.append("<p>" + news.getStart());
+      if (news.getEnd() != null) {
+        sb.append("&ndash;" + news.getEnd());
+      }
+      sb.append(": ");
+      if (news.getPlace() != null) {
+        sb.append(news.getPlace() + ", ");
+      }
+      if (news.getProtocols() != null) {
+        int written = 0;
+        for (String protocol : news.getProtocols()) {
+          sb.append((written++ > 0 ? ", " : "") + protocol);
+        }
+      }
+      sb.append(", " + news.getDescription());
+      if (news.getLinks() != null && news.getLinks().length > 0) {
+        int written = 0;
+        sb.append(" (");
+        for (String link : news.getLinks()) {
+          sb.append((written++ > 0 ? " " : "") + link);
+        }
+        sb.append(")");
+      }
+      sb.append("</p>");
+      String[] formattedNews = new String[] { sb.toString() };
+      for (Map.Entry<String, String> category : cutOffDates.entrySet()) {
+        if (news.getStart().compareTo(category.getKey()) >= 0) {
+          newsByCategory.get(category.getValue()).add(formattedNews);
+          break;
+        }
+      }
+    }
+
+    /* Remove categories without news. */
+    for (String category : cutOffDates.values()) {
+      if (newsByCategory.get(category).isEmpty()) {
+        newsByCategory.remove(category);
+      }
+    }
+
+    /* Pass news by category to the JSP and let it do the rest of the work. */
+    request.setAttribute("news", newsByCategory);
     request.getRequestDispatcher("WEB-INF/news.jsp").forward(request,
         response);
   }
diff --git a/website/src/org/torproject/metrics/web/graphs/GraphParameterChecker.java b/website/src/org/torproject/metrics/web/graphs/GraphParameterChecker.java
index b40885c..9f2a774 100644
--- a/website/src/org/torproject/metrics/web/graphs/GraphParameterChecker.java
+++ b/website/src/org/torproject/metrics/web/graphs/GraphParameterChecker.java
@@ -3,8 +3,8 @@
 
 package org.torproject.metrics.web.graphs;
 
+import org.torproject.metrics.web.ContentProvider;
 import org.torproject.metrics.web.Metric;
-import org.torproject.metrics.web.MetricsProvider;
 
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -50,7 +50,7 @@ public class GraphParameterChecker {
     this.dateFormat = new SimpleDateFormat("yyyy-MM-dd");
     this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
     this.availableGraphs = new HashMap<String, String[]>();
-    for (Metric metric : MetricsProvider.getInstance().getMetricsList()) {
+    for (Metric metric : ContentProvider.getInstance().getMetricsList()) {
       if ("Graph".equals(metric.getType())) {
         this.availableGraphs.put(metric.getId(), metric.getParameters());
       }
diff --git a/website/src/org/torproject/metrics/web/graphs/RObjectGenerator.java b/website/src/org/torproject/metrics/web/graphs/RObjectGenerator.java
index 526e3d3..87f3e33 100644
--- a/website/src/org/torproject/metrics/web/graphs/RObjectGenerator.java
+++ b/website/src/org/torproject/metrics/web/graphs/RObjectGenerator.java
@@ -3,8 +3,8 @@
 
 package org.torproject.metrics.web.graphs;
 
+import org.torproject.metrics.web.ContentProvider;
 import org.torproject.metrics.web.Metric;
-import org.torproject.metrics.web.MetricsProvider;
 
 import org.rosuda.REngine.Rserve.RConnection;
 import org.rosuda.REngine.Rserve.RserveException;
@@ -59,7 +59,7 @@ public class RObjectGenerator implements ServletContextListener {
 
     this.availableGraphs = new LinkedHashMap<String, Metric>();
     this.availableTables = new LinkedHashMap<String, Metric>();
-    for (Metric metric : MetricsProvider.getInstance().getMetricsList()) {
+    for (Metric metric : ContentProvider.getInstance().getMetricsList()) {
       String type = metric.getType();
       String id = metric.getId();
       if ("Graph".equals(type)) {
diff --git a/website/src/org/torproject/metrics/web/graphs/TableParameterChecker.java b/website/src/org/torproject/metrics/web/graphs/TableParameterChecker.java
index b441ab6..c068b7d 100644
--- a/website/src/org/torproject/metrics/web/graphs/TableParameterChecker.java
+++ b/website/src/org/torproject/metrics/web/graphs/TableParameterChecker.java
@@ -3,8 +3,8 @@
 
 package org.torproject.metrics.web.graphs;
 
+import org.torproject.metrics.web.ContentProvider;
 import org.torproject.metrics.web.Metric;
-import org.torproject.metrics.web.MetricsProvider;
 
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
@@ -47,7 +47,7 @@ public class TableParameterChecker {
     this.dateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
 
     this.availableTables = new HashMap<String, String[]>();
-    for (Metric metric : MetricsProvider.getInstance().getMetricsList()) {
+    for (Metric metric : ContentProvider.getInstance().getMetricsList()) {
       if ("Table".equals(metric.getType())) {
         this.availableTables.put(metric.getId(), metric.getParameters());
       }
diff --git a/website/web/WEB-INF/news.jsp b/website/web/WEB-INF/news.jsp
index c47c1b8..61c81b0 100644
--- a/website/web/WEB-INF/news.jsp
+++ b/website/web/WEB-INF/news.jsp
@@ -33,6 +33,13 @@ of data, rather than just dogma or perspective."
 <h3>News</h3>
 <br>
 
+<c:forEach var="category" items="${news}">
+<h3>${category.key}</h3>
+<c:forEach var="entry" items="${category.value}">
+<p>${entry[0]}</p>
+</c:forEach>
+</c:forEach>
+
     </div>
   </div>
   <div class="bottom" id="bottom">



_______________________________________________
tor-commits mailing list
tor-commits@xxxxxxxxxxxxxxxxxxxx
https://lists.torproject.org/cgi-bin/mailman/listinfo/tor-commits