[tor-commits] [metrics-web/master] Provide graphs for all countries in the GeoIP database.

karsten at torproject.org karsten at torproject.org
Fri Apr 22 02:57:53 UTC 2011


commit f5116c6087b8cfd18b53268b56d9097218c43123
Author: Karsten Loesing <karsten.loesing at gmx.net>
Date:   Thu Apr 21 21:47:12 2011 +0200

    Provide graphs for all countries in the GeoIP database.
---
 rserve/graphs.R                                    |  312 ++++++++++++++++---
 src/org/torproject/ernie/web/Countries.java        |  282 ++++++++++++++++++
 .../ernie/web/GraphParameterChecker.java           |    8 +-
 .../ernie/web/GraphsSubpagesServlet.java           |    8 +
 web/WEB-INF/network.jsp                            |   45 +---
 web/WEB-INF/users.jsp                              |   90 +------
 6 files changed, 566 insertions(+), 179 deletions(-)

diff --git a/rserve/graphs.R b/rserve/graphs.R
index 3e56cc8..15daf02 100644
--- a/rserve/graphs.R
+++ b/rserve/graphs.R
@@ -1,3 +1,259 @@
+countrylist <- list(
+  "ad" = "Andorra",
+  "ae" = "the United Arab Emirates",
+  "af" = "Afghanistan",
+  "ag" = "Antigua and Barbuda",
+  "ai" = "Anguilla",
+  "al" = "Albania",
+  "am" = "Armenia",
+  "an" = "the Netherlands Antilles",
+  "ao" = "Angola",
+  "aq" = "Antarctica",
+  "ar" = "Argentina",
+  "as" = "American Samoa",
+  "at" = "Austria",
+  "au" = "Australia",
+  "aw" = "Aruba",
+  "ax" = "the Aland Islands",
+  "az" = "Azerbaijan",
+  "ba" = "Bosnia and Herzegovina",
+  "bb" = "Barbados",
+  "bd" = "Bangladesh",
+  "be" = "Belgium",
+  "bf" = "Burkina Faso",
+  "bg" = "Bulgaria",
+  "bh" = "Bahrain",
+  "bi" = "Burundi",
+  "bj" = "Benin",
+  "bl" = "Saint Bartelemey",
+  "bm" = "Bermuda",
+  "bn" = "Brunei Darussalam",
+  "bo" = "Bolivia",
+  "br" = "Brazil",
+  "bs" = "the Bahamas",
+  "bt" = "Bhutan",
+  "bv" = "the Bouvet Island",
+  "bw" = "Botswana",
+  "by" = "Belarus",
+  "bz" = "Belize",
+  "ca" = "Canada",
+  "cc" = "the Cocos (Keeling) Islands",
+  "cd" = "the Democratic Republic of the Congo",
+  "cf" = "Central African Republic",
+  "cg" = "Congo",
+  "ch" = "Switzerland",
+  "ci" = "Cote d'Ivoire",
+  "ck" = "the Cook Islands",
+  "cl" = "Chile",
+  "cm" = "Cameroon",
+  "cn" = "China",
+  "co" = "Colombia",
+  "cr" = "Costa Rica",
+  "cu" = "Cuba",
+  "cv" = "Cape Verde",
+  "cx" = "the Christmas Island",
+  "cy" = "Cyprus",
+  "cz" = "the Czech Republic",
+  "de" = "Germany",
+  "dj" = "Djibouti",
+  "dk" = "Denmark",
+  "dm" = "Dominica",
+  "do" = "the Dominican Republic",
+  "dz" = "Algeria",
+  "ec" = "Ecuador",
+  "ee" = "Estonia",
+  "eg" = "Egypt",
+  "eh" = "the Western Sahara",
+  "er" = "Eritrea",
+  "es" = "Spain",
+  "et" = "Ethiopia",
+  "fi" = "Finland",
+  "fj" = "Fiji",
+  "fk" = "the Falkland Islands (Malvinas)",
+  "fm" = "the Federated States of Micronesia",
+  "fo" = "the Faroe Islands",
+  "fr" = "France",
+  "fx" = "Metropolitan France",
+  "ga" = "Gabon",
+  "gb" = "the United Kingdom",
+  "gd" = "Grenada",
+  "ge" = "Georgia",
+  "gf" = "French Guiana",
+  "gg" = "Guernsey",
+  "gh" = "Ghana",
+  "gi" = "Gibraltar",
+  "gl" = "Greenland",
+  "gm" = "Gambia",
+  "gn" = "Guinea",
+  "gp" = "Guadeloupe",
+  "gq" = "Equatorial Guinea",
+  "gr" = "Greece",
+  "gs" = "South Georgia and the South Sandwich Islands",
+  "gt" = "Guatemala",
+  "gu" = "Guam",
+  "gw" = "Guinea-Bissau",
+  "gy" = "Guyana",
+  "hk" = "Hong Kong",
+  "hm" = "Heard Island and McDonald Islands",
+  "hn" = "Honduras",
+  "hr" = "Croatia",
+  "ht" = "Haiti",
+  "hu" = "Hungary",
+  "id" = "Indonesia",
+  "ie" = "Ireland",
+  "il" = "Israel",
+  "im" = "the Isle of Man",
+  "in" = "India",
+  "io" = "the British Indian Ocean Territory",
+  "iq" = "Iraq",
+  "ir" = "the Islamic Republic of Iran",
+  "is" = "Iceland",
+  "it" = "Italy",
+  "je" = "Jersey",
+  "jm" = "Jamaica",
+  "jo" = "Jordan",
+  "jp" = "Japan",
+  "ke" = "Kenya",
+  "kg" = "Kyrgyzstan",
+  "kh" = "Cambodia",
+  "ki" = "Kiribati",
+  "km" = "Comoros",
+  "kn" = "Saint Kitts and Nevis",
+  "kp" = "the Democratic People's Republic of Korea",
+  "kr" = "the Republic of Korea",
+  "kw" = "Kuwait",
+  "ky" = "the Cayman Islands",
+  "kz" = "Kazakhstan",
+  "la" = "Lao People's Democratic Republic",
+  "lb" = "Lebanon",
+  "lc" = "Saint Lucia",
+  "li" = "Liechtenstein",
+  "lk" = "Sri Lanka",
+  "lr" = "Liberia",
+  "ls" = "Lesotho",
+  "lt" = "Lithuania",
+  "lu" = "Luxembourg",
+  "lv" = "Latvia",
+  "ly" = "Libyan Arab Jamahiriya",
+  "ma" = "Morocco",
+  "mc" = "Monaco",
+  "md" = "the Republic of Moldova",
+  "me" = "Montenegro",
+  "mf" = "Saint Martin",
+  "mg" = "Madagascar",
+  "mh" = "the Marshall Islands",
+  "mk" = "Macedonia",
+  "ml" = "Mali",
+  "mm" = "Myanmar",
+  "mn" = "Mongolia",
+  "mo" = "Macao",
+  "mp" = "the Northern Mariana Islands",
+  "mq" = "Martinique",
+  "mr" = "Mauritania",
+  "ms" = "Montserrat",
+  "mt" = "Malta",
+  "mu" = "Mauritius",
+  "mv" = "the Maldives",
+  "mw" = "Malawi",
+  "mx" = "Mexico",
+  "my" = "Malaysia",
+  "mz" = "Mozambique",
+  "na" = "Namibia",
+  "nc" = "New Caledonia",
+  "ne" = "Niger",
+  "nf" = "Norfolk Island",
+  "ng" = "Nigeria",
+  "ni" = "Nicaragua",
+  "nl" = "the Netherlands",
+  "no" = "Norway",
+  "np" = "Nepal",
+  "nr" = "Nauru",
+  "nu" = "Niue",
+  "nz" = "New Zealand",
+  "om" = "Oman",
+  "pa" = "Panama",
+  "pe" = "Peru",
+  "pf" = "French Polynesia",
+  "pg" = "Papua New Guinea",
+  "ph" = "the Philippines",
+  "pk" = "Pakistan",
+  "pl" = "Poland",
+  "pm" = "Saint Pierre and Miquelon",
+  "pn" = "Pitcairn",
+  "pr" = "Puerto Rico",
+  "ps" = "the Palestinian Territory",
+  "pt" = "Portugal",
+  "pw" = "Palau",
+  "py" = "Paraguay",
+  "qa" = "Qatar",
+  "re" = "Reunion",
+  "ro" = "Romania",
+  "rs" = "Serbia",
+  "ru" = "the Russian Federation",
+  "rw" = "Rwanda",
+  "sa" = "Saudi Arabia",
+  "sb" = "the Solomon Islands",
+  "sc" = "the Seychelles",
+  "sd" = "Sudan",
+  "se" = "Sweden",
+  "sg" = "Singapore",
+  "sh" = "Saint Helena",
+  "si" = "Slovenia",
+  "sj" = "Svalbard and Jan Mayen",
+  "sk" = "Slovakia",
+  "sl" = "Sierra Leone",
+  "sm" = "San Marino",
+  "sn" = "Senegal",
+  "so" = "Somalia",
+  "sr" = "Suriname",
+  "st" = "Sao Tome and Principe",
+  "sv" = "El Salvador",
+  "sy" = "the Syrian Arab Republic",
+  "sz" = "Swaziland",
+  "tc" = "Turks and Caicos Islands",
+  "td" = "Chad",
+  "tf" = "the French Southern Territories",
+  "tg" = "Togo",
+  "th" = "Thailand",
+  "tj" = "Tajikistan",
+  "tk" = "Tokelau",
+  "tl" = "Timor-Leste",
+  "tm" = "Turkmenistan",
+  "tn" = "Tunisia",
+  "to" = "Tonga",
+  "tr" = "Turkey",
+  "tt" = "Trinidad and Tobago",
+  "tv" = "Tuvalu",
+  "tw" = "Taiwan",
+  "tz" = "the United Republic of Tanzania",
+  "ua" = "Ukraine",
+  "ug" = "Uganda",
+  "um" = "the United States Minor Outlying Islands",
+  "us" = "the United States",
+  "uy" = "Uruguay",
+  "uz" = "Uzbekistan",
+  "va" = "Vatican City State",
+  "vc" = "Saint Vincent and the Grenadines",
+  "ve" = "Venezuela",
+  "vg" = "the British Virgin Islands",
+  "vi" = "the United States Virgin Islands",
+  "vn" = "Vietnam",
+  "vu" = "Vanuatu",
+  "wf" = "Wallis and Futuna",
+  "ws" = "Samoa",
+  "ye" = "Yemen",
+  "yt" = "Mayotte",
+  "za" = "South Africa",
+  "zm" = "Zambia",
+  "zw" = "Zimbabwe")
+
+countryname <- function(country) {
+  res <- countrylist[[country]]
+  if (is.null(res))
+    res <- "no-man's-land"
+  res
+}
+
 plot_networksize <- function(start, end, path, dpi) {
   drv <- dbDriver("PostgreSQL")
   con <- dbConnect(drv, user = dbuser, password = dbpassword, dbname = db)
@@ -69,24 +325,9 @@ plot_relaycountries <- function(start, end, country, path, dpi) {
     u <- rbind(u,
         data.frame(date = as.Date(missing, origin = "1970-01-01"),
         relays = NA))
-  peoples <- data.frame(country = c("ae", "au", "bh", "br", "ca", "cn",
-    "cu", "de", "dj", "dz", "eg", "et", "fr", "gb", "il", "ir", "it",
-    "iq", "jo", "jp", "kp", "kr", "kw", "lb", "ly", "ma", "mm", "om",
-    "pl", "ps", "qa", "ru", "sa", "sd", "se", "sy", "tn", "tm", "us",
-    "uz", "vn", "ye"),
-    people = c("U.A.E.", "Australian", "Bahraini", "Brazilian",
-    "Canadian", "Chinese", "Cuban", "German", "Djiboutian", "Algerian",
-    "Egyptian", "Ethiopian", "French", "U.K.", "Israeli", "Iranian",
-    "Italian", "Iraqi", "Jordanian", "Japanese", "North Korean",
-    "South Korean", "Kuwaiti", "Lebanese", "Libyan", "Moroccan",
-    "Burmese", "Omani", "Polish", "Palestinian", "Qatari", "Russian",
-    "Saudi", "Sudanese", "Swedish", "Syrian", "Tunisian", "Turkmen",
-    "U.S.", "Uzbek", "Vietnamese", "Yemeni"),
-    stringsAsFactors = FALSE)
   title <- ifelse(country == "all",
     "Number of relays in all countries\n",
-    paste("Number of", peoples[peoples$country == country, "people"],
-      "relays\n"))
+    paste("Number of relays in ", countryname(country), "\n", sep = ""))
   formatter <- function(x, ...) { format(x, scientific = FALSE, ...) }
   ggplot(u, aes(x = as.Date(date, "%Y-%m-%d"), y = relays)) +
     geom_line(size = 1) +
@@ -318,24 +559,10 @@ plot_direct_users <- function(start, end, country, path, dpi) {
     u <- rbind(u,
         data.frame(date = as.Date(missing, origin = "1970-01-01"),
         users = NA))
-  peoples <- data.frame(country = c("ae", "au", "bh", "br", "ca", "cn",
-    "cu", "de", "dj", "dz", "eg", "et", "fr", "gb", "il", "ir", "it",
-    "iq", "jo", "jp", "kp", "kr", "kw", "lb", "ly", "ma", "mm", "om",
-    "pl", "ps", "qa", "ru", "sa", "sd", "se", "sy", "tn", "tm", "us",
-    "uz", "vn", "ye"),
-    people = c("U.A.E.", "Australian", "Bahraini", "Brazilian",
-    "Canadian", "Chinese", "Cuban", "German", "Djiboutian", "Algerian",
-    "Egyptian", "Ethiopian", "French", "U.K.", "Israeli", "Iranian",
-    "Italian", "Iraqi", "Jordanian", "Japanese", "North Korean",
-    "South Korean", "Kuwaiti", "Lebanese", "Libyan", "Moroccan",
-    "Burmese", "Omani", "Polish", "Palestinian", "Qatari", "Russian",
-    "Saudi", "Sudanese", "Swedish", "Syrian", "Tunisian", "Turkmen",
-    "U.S.", "Uzbek", "Vietnamese", "Yemeni"),
-    stringsAsFactors = FALSE)
   title <- ifelse(country == "all",
-    "Total directly connecting Tor users (all data)\n",
-    paste("Directly connecting",
-    peoples[peoples$country == country, "people"], "Tor users\n"))
+    "Directly connecting users from all countries\n",
+    paste("Directly connecting users from ", countryname(country), "\n",
+      sep = ""))
   formatter <- function(x, ...) { format(x, scientific = FALSE, ...) }
   ggplot(u, aes(x = as.Date(date, "%Y-%m-%d"), y = users)) +
     geom_line(size = 1) +
@@ -370,24 +597,9 @@ plot_bridge_users <- function(start, end, country, path, dpi) {
     bridgeusers <- rbind(bridgeusers,
         data.frame(date = as.Date(missing, origin = "1970-01-01"),
         users = NA))
-  peoples <- data.frame(country = c("ae", "au", "bh", "br", "ca", "cn",
-    "cu", "de", "dj", "dz", "eg", "et", "fr", "gb", "il", "ir", "it",
-    "iq", "jo", "jp", "kp", "kr", "kw", "lb", "ly", "ma", "mm", "om",
-    "pl", "ps", "qa", "ru", "sa", "sd", "se", "sy", "tn", "tm", "us",
-    "uz", "vn", "ye"),
-    people = c("U.A.E.", "Australian", "Bahraini", "Brazilian",
-    "Canadian", "Chinese", "Cuban", "German", "Djiboutian", "Algerian",
-    "Egyptian", "Ethiopian", "French", "U.K.", "Israeli", "Iranian",
-    "Italian", "Iraqi", "Jordanian", "Japanese", "North Korean",
-    "South Korean", "Kuwaiti", "Lebanese", "Libyan", "Moroccan",
-    "Burmese", "Omani", "Polish", "Palestinian", "Qatari", "Russian",
-    "Saudi", "Sudanese", "Swedish", "Syrian", "Tunisian", "Turkmen",
-    "U.S.", "Uzbek", "Vietnamese", "Yemeni"),
-    stringsAsFactors = FALSE)
   title <- ifelse(country == "all",
-    "Total users via bridges (all data)\n",
-    paste(peoples[peoples$country == country, "people"],
-    "users via bridges\n"))
+    "Bridge users from all countries\n",
+    paste("Bridge users from ", countryname(country), "\n", sep = ""))
   formatter <- function(x, ...) { format(x, scientific = FALSE, ...) }
   ggplot(bridgeusers, aes(x = as.Date(date, "%Y-%m-%d"), y = users)) +
     geom_line(size = 1) +
diff --git a/src/org/torproject/ernie/web/Countries.java b/src/org/torproject/ernie/web/Countries.java
new file mode 100644
index 0000000..6829488
--- /dev/null
+++ b/src/org/torproject/ernie/web/Countries.java
@@ -0,0 +1,282 @@
+package org.torproject.ernie.web;
+
+import java.util.*;
+
+public class Countries {
+
+  private static Countries instance = new Countries();
+
+  public static Countries getInstance() {
+    return Countries.instance;
+  }
+
+  /* List of arrays of length 2, containing country codes at [0] and
+   * country names at [1], alphabetically ordered by country names. */
+  private List<String[]> knownCountries;
+
+  private Countries() {
+    this.knownCountries = new ArrayList<String[]>();
+    this.knownCountries.add("af;Afghanistan".split(";"));
+    this.knownCountries.add("ax;Aland Islands".split(";"));
+    this.knownCountries.add("al;Albania".split(";"));
+    this.knownCountries.add("dz;Algeria".split(";"));
+    this.knownCountries.add("as;American Samoa".split(";"));
+    this.knownCountries.add("ad;Andorra".split(";"));
+    this.knownCountries.add("ao;Angola".split(";"));
+    this.knownCountries.add("ai;Anguilla".split(";"));
+    this.knownCountries.add("aq;Antarctica".split(";"));
+    this.knownCountries.add("ag;Antigua and Barbuda".split(";"));
+    this.knownCountries.add("ar;Argentina".split(";"));
+    this.knownCountries.add("am;Armenia".split(";"));
+    this.knownCountries.add("aw;Aruba".split(";"));
+    this.knownCountries.add("au;Australia".split(";"));
+    this.knownCountries.add("at;Austria".split(";"));
+    this.knownCountries.add("az;Azerbaijan".split(";"));
+    this.knownCountries.add("bs;Bahamas".split(";"));
+    this.knownCountries.add("bh;Bahrain".split(";"));
+    this.knownCountries.add("bd;Bangladesh".split(";"));
+    this.knownCountries.add("bb;Barbados".split(";"));
+    this.knownCountries.add("by;Belarus".split(";"));
+    this.knownCountries.add("be;Belgium".split(";"));
+    this.knownCountries.add("bz;Belize".split(";"));
+    this.knownCountries.add("bj;Benin".split(";"));
+    this.knownCountries.add("bm;Bermuda".split(";"));
+    this.knownCountries.add("bt;Bhutan".split(";"));
+    this.knownCountries.add("bo;Bolivia".split(";"));
+    this.knownCountries.add("ba;Bosnia and Herzegovina".split(";"));
+    this.knownCountries.add("bw;Botswana".split(";"));
+    this.knownCountries.add("bv;Bouvet Island".split(";"));
+    this.knownCountries.add("br;Brazil".split(";"));
+    this.knownCountries.add("io;British Indian Ocean Territory".
+        split(";"));
+    this.knownCountries.add("bn;Brunei Darussalam".split(";"));
+    this.knownCountries.add("bg;Bulgaria".split(";"));
+    this.knownCountries.add("bf;Burkina Faso".split(";"));
+    this.knownCountries.add("bi;Burundi".split(";"));
+    this.knownCountries.add("kh;Cambodia".split(";"));
+    this.knownCountries.add("cm;Cameroon".split(";"));
+    this.knownCountries.add("ca;Canada".split(";"));
+    this.knownCountries.add("cv;Cape Verde".split(";"));
+    this.knownCountries.add("ky;Cayman Islands".split(";"));
+    this.knownCountries.add("cf;Central African Republic".split(";"));
+    this.knownCountries.add("td;Chad".split(";"));
+    this.knownCountries.add("cl;Chile".split(";"));
+    this.knownCountries.add("cn;China".split(";"));
+    this.knownCountries.add("cx;Christmas Island".split(";"));
+    this.knownCountries.add("cc;Cocos (Keeling) Islands".split(";"));
+    this.knownCountries.add("co;Colombia".split(";"));
+    this.knownCountries.add("km;Comoros".split(";"));
+    this.knownCountries.add("cd;Congo, The Democratic Republic of the".
+        split(";"));
+    this.knownCountries.add("cg;Congo".split(";"));
+    this.knownCountries.add("ck;Cook Islands".split(";"));
+    this.knownCountries.add("cr;Costa Rica".split(";"));
+    this.knownCountries.add("ci;Cote d'Ivoire".split(";"));
+    this.knownCountries.add("hr;Croatia".split(";"));
+    this.knownCountries.add("cu;Cuba".split(";"));
+    this.knownCountries.add("cy;Cyprus".split(";"));
+    this.knownCountries.add("cz;Czech Republic".split(";"));
+    this.knownCountries.add("dk;Denmark".split(";"));
+    this.knownCountries.add("dj;Djibouti".split(";"));
+    this.knownCountries.add("dm;Dominica".split(";"));
+    this.knownCountries.add("do;Dominican Republic".split(";"));
+    this.knownCountries.add("ec;Ecuador".split(";"));
+    this.knownCountries.add("eg;Egypt".split(";"));
+    this.knownCountries.add("sv;El Salvador".split(";"));
+    this.knownCountries.add("gq;Equatorial Guinea".split(";"));
+    this.knownCountries.add("er;Eritrea".split(";"));
+    this.knownCountries.add("ee;Estonia".split(";"));
+    this.knownCountries.add("et;Ethiopia".split(";"));
+    this.knownCountries.add("fk;Falkland Islands (Malvinas)".split(";"));
+    this.knownCountries.add("fo;Faroe Islands".split(";"));
+    this.knownCountries.add("fj;Fiji".split(";"));
+    this.knownCountries.add("fi;Finland".split(";"));
+    this.knownCountries.add("fx;France, Metropolitan".split(";"));
+    this.knownCountries.add("fr;France".split(";"));
+    this.knownCountries.add("gf;French Guiana".split(";"));
+    this.knownCountries.add("pf;French Polynesia".split(";"));
+    this.knownCountries.add("tf;French Southern Territories".split(";"));
+    this.knownCountries.add("ga;Gabon".split(";"));
+    this.knownCountries.add("gm;Gambia".split(";"));
+    this.knownCountries.add("ge;Georgia".split(";"));
+    this.knownCountries.add("de;Germany".split(";"));
+    this.knownCountries.add("gh;Ghana".split(";"));
+    this.knownCountries.add("gi;Gibraltar".split(";"));
+    this.knownCountries.add("gr;Greece".split(";"));
+    this.knownCountries.add("gl;Greenland".split(";"));
+    this.knownCountries.add("gd;Grenada".split(";"));
+    this.knownCountries.add("gp;Guadeloupe".split(";"));
+    this.knownCountries.add("gu;Guam".split(";"));
+    this.knownCountries.add("gt;Guatemala".split(";"));
+    this.knownCountries.add("gg;Guernsey".split(";"));
+    this.knownCountries.add("gn;Guinea".split(";"));
+    this.knownCountries.add("gw;Guinea-Bissau".split(";"));
+    this.knownCountries.add("gy;Guyana".split(";"));
+    this.knownCountries.add("ht;Haiti".split(";"));
+    this.knownCountries.add("hm;Heard Island and McDonald Islands".
+        split(";"));
+    this.knownCountries.add("va;Holy See (Vatican City State)".
+        split(";"));
+    this.knownCountries.add("hn;Honduras".split(";"));
+    this.knownCountries.add("hk;Hong Kong".split(";"));
+    this.knownCountries.add("hu;Hungary".split(";"));
+    this.knownCountries.add("is;Iceland".split(";"));
+    this.knownCountries.add("in;India".split(";"));
+    this.knownCountries.add("id;Indonesia".split(";"));
+    this.knownCountries.add("ir;Iran, Islamic Republic of".split(";"));
+    this.knownCountries.add("iq;Iraq".split(";"));
+    this.knownCountries.add("ie;Ireland".split(";"));
+    this.knownCountries.add("im;Isle of Man".split(";"));
+    this.knownCountries.add("il;Israel".split(";"));
+    this.knownCountries.add("it;Italy".split(";"));
+    this.knownCountries.add("jm;Jamaica".split(";"));
+    this.knownCountries.add("jp;Japan".split(";"));
+    this.knownCountries.add("je;Jersey".split(";"));
+    this.knownCountries.add("jo;Jordan".split(";"));
+    this.knownCountries.add("kz;Kazakhstan".split(";"));
+    this.knownCountries.add("ke;Kenya".split(";"));
+    this.knownCountries.add("ki;Kiribati".split(";"));
+    this.knownCountries.add("kp;Korea, Democratic People's Republic of".
+        split(";"));
+    this.knownCountries.add("kr;Korea, Republic of".split(";"));
+    this.knownCountries.add("kw;Kuwait".split(";"));
+    this.knownCountries.add("kg;Kyrgyzstan".split(";"));
+    this.knownCountries.add("la;Lao People's Democratic Republic".
+        split(";"));
+    this.knownCountries.add("lv;Latvia".split(";"));
+    this.knownCountries.add("lb;Lebanon".split(";"));
+    this.knownCountries.add("ls;Lesotho".split(";"));
+    this.knownCountries.add("lr;Liberia".split(";"));
+    this.knownCountries.add("ly;Libyan Arab Jamahiriya".split(";"));
+    this.knownCountries.add("li;Liechtenstein".split(";"));
+    this.knownCountries.add("lt;Lithuania".split(";"));
+    this.knownCountries.add("lu;Luxembourg".split(";"));
+    this.knownCountries.add("mo;Macao".split(";"));
+    this.knownCountries.add("mk;Macedonia".split(";"));
+    this.knownCountries.add("mg;Madagascar".split(";"));
+    this.knownCountries.add("mw;Malawi".split(";"));
+    this.knownCountries.add("my;Malaysia".split(";"));
+    this.knownCountries.add("mv;Maldives".split(";"));
+    this.knownCountries.add("ml;Mali".split(";"));
+    this.knownCountries.add("mt;Malta".split(";"));
+    this.knownCountries.add("mh;Marshall Islands".split(";"));
+    this.knownCountries.add("mq;Martinique".split(";"));
+    this.knownCountries.add("mr;Mauritania".split(";"));
+    this.knownCountries.add("mu;Mauritius".split(";"));
+    this.knownCountries.add("yt;Mayotte".split(";"));
+    this.knownCountries.add("mx;Mexico".split(";"));
+    this.knownCountries.add("fm;Micronesia, Federated States of".
+        split(";"));
+    this.knownCountries.add("md;Moldova, Republic of".split(";"));
+    this.knownCountries.add("mc;Monaco".split(";"));
+    this.knownCountries.add("mn;Mongolia".split(";"));
+    this.knownCountries.add("me;Montenegro".split(";"));
+    this.knownCountries.add("ms;Montserrat".split(";"));
+    this.knownCountries.add("ma;Morocco".split(";"));
+    this.knownCountries.add("mz;Mozambique".split(";"));
+    this.knownCountries.add("mm;Myanmar".split(";"));
+    this.knownCountries.add("na;Namibia".split(";"));
+    this.knownCountries.add("nr;Nauru".split(";"));
+    this.knownCountries.add("np;Nepal".split(";"));
+    this.knownCountries.add("an;Netherlands Antilles".split(";"));
+    this.knownCountries.add("nl;Netherlands".split(";"));
+    this.knownCountries.add("nc;New Caledonia".split(";"));
+    this.knownCountries.add("nz;New Zealand".split(";"));
+    this.knownCountries.add("ni;Nicaragua".split(";"));
+    this.knownCountries.add("ne;Niger".split(";"));
+    this.knownCountries.add("ng;Nigeria".split(";"));
+    this.knownCountries.add("nu;Niue".split(";"));
+    this.knownCountries.add("nf;Norfolk Island".split(";"));
+    this.knownCountries.add("mp;Northern Mariana Islands".split(";"));
+    this.knownCountries.add("no;Norway".split(";"));
+    this.knownCountries.add("om;Oman".split(";"));
+    this.knownCountries.add("pk;Pakistan".split(";"));
+    this.knownCountries.add("pw;Palau".split(";"));
+    this.knownCountries.add("ps;Palestinian Territory".split(";"));
+    this.knownCountries.add("pa;Panama".split(";"));
+    this.knownCountries.add("pg;Papua New Guinea".split(";"));
+    this.knownCountries.add("py;Paraguay".split(";"));
+    this.knownCountries.add("pe;Peru".split(";"));
+    this.knownCountries.add("ph;Philippines".split(";"));
+    this.knownCountries.add("pn;Pitcairn".split(";"));
+    this.knownCountries.add("pl;Poland".split(";"));
+    this.knownCountries.add("pt;Portugal".split(";"));
+    this.knownCountries.add("pr;Puerto Rico".split(";"));
+    this.knownCountries.add("qa;Qatar".split(";"));
+    this.knownCountries.add("re;Reunion".split(";"));
+    this.knownCountries.add("ro;Romania".split(";"));
+    this.knownCountries.add("ru;Russian Federation".split(";"));
+    this.knownCountries.add("rw;Rwanda".split(";"));
+    this.knownCountries.add("bl;Saint Bartelemey".split(";"));
+    this.knownCountries.add("sh;Saint Helena".split(";"));
+    this.knownCountries.add("kn;Saint Kitts and Nevis".split(";"));
+    this.knownCountries.add("lc;Saint Lucia".split(";"));
+    this.knownCountries.add("mf;Saint Martin".split(";"));
+    this.knownCountries.add("pm;Saint Pierre and Miquelon".split(";"));
+    this.knownCountries.add("vc;Saint Vincent and the Grenadines".
+        split(";"));
+    this.knownCountries.add("ws;Samoa".split(";"));
+    this.knownCountries.add("sm;San Marino".split(";"));
+    this.knownCountries.add("st;Sao Tome and Principe".split(";"));
+    this.knownCountries.add("sa;Saudi Arabia".split(";"));
+    this.knownCountries.add("sn;Senegal".split(";"));
+    this.knownCountries.add("rs;Serbia".split(";"));
+    this.knownCountries.add("sc;Seychelles".split(";"));
+    this.knownCountries.add("sl;Sierra Leone".split(";"));
+    this.knownCountries.add("sg;Singapore".split(";"));
+    this.knownCountries.add("sk;Slovakia".split(";"));
+    this.knownCountries.add("si;Slovenia".split(";"));
+    this.knownCountries.add("sb;Solomon Islands".split(";"));
+    this.knownCountries.add("so;Somalia".split(";"));
+    this.knownCountries.add("za;South Africa".split(";"));
+    this.knownCountries.add(("gs;South Georgia and the South Sandwich "
+        + "Islands").split(";"));
+    this.knownCountries.add("es;Spain".split(";"));
+    this.knownCountries.add("lk;Sri Lanka".split(";"));
+    this.knownCountries.add("sd;Sudan".split(";"));
+    this.knownCountries.add("sr;Suriname".split(";"));
+    this.knownCountries.add("sj;Svalbard and Jan Mayen".split(";"));
+    this.knownCountries.add("sz;Swaziland".split(";"));
+    this.knownCountries.add("se;Sweden".split(";"));
+    this.knownCountries.add("ch;Switzerland".split(";"));
+    this.knownCountries.add("sy;Syrian Arab Republic".split(";"));
+    this.knownCountries.add("tw;Taiwan".split(";"));
+    this.knownCountries.add("tj;Tajikistan".split(";"));
+    this.knownCountries.add("tz;Tanzania, United Republic of".split(";"));
+    this.knownCountries.add("th;Thailand".split(";"));
+    this.knownCountries.add("tl;Timor-Leste".split(";"));
+    this.knownCountries.add("tg;Togo".split(";"));
+    this.knownCountries.add("tk;Tokelau".split(";"));
+    this.knownCountries.add("to;Tonga".split(";"));
+    this.knownCountries.add("tt;Trinidad and Tobago".split(";"));
+    this.knownCountries.add("tn;Tunisia".split(";"));
+    this.knownCountries.add("tr;Turkey".split(";"));
+    this.knownCountries.add("tm;Turkmenistan".split(";"));
+    this.knownCountries.add("tc;Turks and Caicos Islands".split(";"));
+    this.knownCountries.add("tv;Tuvalu".split(";"));
+    this.knownCountries.add("ug;Uganda".split(";"));
+    this.knownCountries.add("ua;Ukraine".split(";"));
+    this.knownCountries.add("ae;United Arab Emirates".split(";"));
+    this.knownCountries.add("gb;United Kingdom".split(";"));
+    this.knownCountries.add("um;United States Minor Outlying Islands".
+        split(";"));
+    this.knownCountries.add("us;United States".split(";"));
+    this.knownCountries.add("uy;Uruguay".split(";"));
+    this.knownCountries.add("uz;Uzbekistan".split(";"));
+    this.knownCountries.add("vu;Vanuatu".split(";"));
+    this.knownCountries.add("ve;Venezuela".split(";"));
+    this.knownCountries.add("vn;Vietnam".split(";"));
+    this.knownCountries.add("vg;Virgin Islands, British".split(";"));
+    this.knownCountries.add("vi;Virgin Islands, U.S.".split(";"));
+    this.knownCountries.add("wf;Wallis and Futuna".split(";"));
+    this.knownCountries.add("eh;Western Sahara".split(";"));
+    this.knownCountries.add("ye;Yemen".split(";"));
+    this.knownCountries.add("zm;Zambia".split(";"));
+    this.knownCountries.add("zw;Zimbabwe".split(";"));
+  }
+
+  public List<String[]> getCountryList() {
+    return this.knownCountries;
+  }
+}
+
diff --git a/src/org/torproject/ernie/web/GraphParameterChecker.java b/src/org/torproject/ernie/web/GraphParameterChecker.java
index 2822cc4..308afe5 100644
--- a/src/org/torproject/ernie/web/GraphParameterChecker.java
+++ b/src/org/torproject/ernie/web/GraphParameterChecker.java
@@ -64,9 +64,11 @@ public class GraphParameterChecker {
     this.knownParameterValues.put("flag",
         "Running,Exit,Guard,Fast,Stable");
     this.knownParameterValues.put("granularity", "day,hour");
-    this.knownParameterValues.put("country", "all,ae,au,bh,br,ca,cn,cu,"
-        + "de,dj,dz,eg,et,fr,gb,il,ir,it,iq,jo,jp,kp,kr,kw,lb,ly,ma,mm,"
-        + "om,pl,ps,qa,ru,sa,sd,se,sy,tn,tm,us,uz,vn,ye");
+    StringBuilder sb = new StringBuilder("all");
+    for (String[] country : Countries.getInstance().getCountryList()) {
+      sb.append("," + country[0]);
+    }
+    this.knownParameterValues.put("country", sb.toString());
     this.knownParameterValues.put("bundle", "all,en,zh_CN,fa");
     this.knownParameterValues.put("source", "all,siv,moria,torperf");
     this.knownParameterValues.put("filesize", "50kb,1mb,5mb");
diff --git a/src/org/torproject/ernie/web/GraphsSubpagesServlet.java b/src/org/torproject/ernie/web/GraphsSubpagesServlet.java
index 1ae39d1..2de2eac 100644
--- a/src/org/torproject/ernie/web/GraphsSubpagesServlet.java
+++ b/src/org/torproject/ernie/web/GraphsSubpagesServlet.java
@@ -11,6 +11,9 @@ public class GraphsSubpagesServlet extends HttpServlet {
    * are forwarded. */
   private Map<String, String> availableGraphsSubpages;
 
+  /* Country codes and names for per-country graphs. */
+  private List<String[]> knownCountries;
+
   public GraphsSubpagesServlet() {
     this.availableGraphsSubpages = new HashMap<String, String>();
     this.availableGraphsSubpages.put("network.html",
@@ -20,6 +23,8 @@ public class GraphsSubpagesServlet extends HttpServlet {
         "WEB-INF/packages.jsp");
     this.availableGraphsSubpages.put("performance.html",
         "WEB-INF/performance.jsp");
+
+    this.knownCountries = Countries.getInstance().getCountryList();
   }
 
   public void doGet(HttpServletRequest request,
@@ -69,6 +74,9 @@ public class GraphsSubpagesServlet extends HttpServlet {
       }
     }
 
+    /* Pass list of known countries in case we want to display them. */
+    request.setAttribute("countries", this.knownCountries);
+
     /* Forward the request to the JSP that does all the hard work. */
     request.getRequestDispatcher(jsp).forward(request, response);
   }
diff --git a/web/WEB-INF/network.jsp b/web/WEB-INF/network.jsp
index 84d5f1d..bba1d4b 100644
--- a/web/WEB-INF/network.jsp
+++ b/web/WEB-INF/network.jsp
@@ -64,48 +64,9 @@ country.</p>
     </p><p>
       Source: <select name="country">
         <option value="all"<c:if test="${relaycountries_country[0] eq 'all'}"> selected</c:if>>All relays</option>
-        <option value="dz"<c:if test="${relaycountries_country[0] eq 'dz'}"> selected</c:if>>Algeria</option>
-        <option value="au"<c:if test="${relaycountries_country[0] eq 'au'}"> selected</c:if>>Australia</option>
-        <option value="bh"<c:if test="${relaycountries_country[0] eq 'bh'}"> selected</c:if>>Bahrain</option>
-        <option value="br"<c:if test="${relaycountries_country[0] eq 'br'}"> selected</c:if>>Brazil</option>
-        <option value="mm"<c:if test="${relaycountries_country[0] eq 'mm'}"> selected</c:if>>Burma</option>
-        <option value="ca"<c:if test="${relaycountries_country[0] eq 'ca'}"> selected</c:if>>Canada</option>
-        <option value="cn"<c:if test="${relaycountries_country[0] eq 'cn'}"> selected</c:if>>China</option>
-        <option value="cu"<c:if test="${relaycountries_country[0] eq 'cu'}"> selected</c:if>>Cuba</option>
-        <option value="dj"<c:if test="${relaycountries_country[0] eq 'dj'}"> selected</c:if>>Djibouti</option>
-        <option value="eg"<c:if test="${relaycountries_country[0] eq 'eg'}"> selected</c:if>>Egypt</option>
-        <option value="et"<c:if test="${relaycountries_country[0] eq 'et'}"> selected</c:if>>Ethiopia</option>
-        <option value="fr"<c:if test="${relaycountries_country[0] eq 'fr'}"> selected</c:if>>France</option>
-        <option value="de"<c:if test="${relaycountries_country[0] eq 'de'}"> selected</c:if>>Germany</option>
-        <option value="ir"<c:if test="${relaycountries_country[0] eq 'ir'}"> selected</c:if>>Iran</option>
-        <option value="iq"<c:if test="${relaycountries_country[0] eq 'iq'}"> selected</c:if>>Iraq</option>
-        <option value="il"<c:if test="${relaycountries_country[0] eq 'il'}"> selected</c:if>>Israel</option>
-        <option value="it"<c:if test="${relaycountries_country[0] eq 'it'}"> selected</c:if>>Italy</option>
-        <option value="jp"<c:if test="${relaycountries_country[0] eq 'jp'}"> selected</c:if>>Japan</option>
-        <option value="jo"<c:if test="${relaycountries_country[0] eq 'jo'}"> selected</c:if>>Jordan</option>
-        <option value="kw"<c:if test="${relaycountries_country[0] eq 'kw'}"> selected</c:if>>Kuwait</option>
-        <option value="lb"<c:if test="${relaycountries_country[0] eq 'lb'}"> selected</c:if>>Lebanon</option>
-        <option value="ly"<c:if test="${relaycountries_country[0] eq 'ly'}"> selected</c:if>>Libya</option>
-        <option value="ma"<c:if test="${relaycountries_country[0] eq 'ma'}"> selected</c:if>>Morocco</option>
-        <option value="kp"<c:if test="${relaycountries_country[0] eq 'kp'}"> selected</c:if>>North Korea</option>
-        <option value="om"<c:if test="${relaycountries_country[0] eq 'om'}"> selected</c:if>>Oman</option>
-        <option value="ps"<c:if test="${relaycountries_country[0] eq 'ps'}"> selected</c:if>>Palestinian territories</option>
-        <option value="pl"<c:if test="${relaycountries_country[0] eq 'pl'}"> selected</c:if>>Poland</option>
-        <option value="qa"<c:if test="${relaycountries_country[0] eq 'qa'}"> selected</c:if>>Qatar</option>
-        <option value="ru"<c:if test="${relaycountries_country[0] eq 'ru'}"> selected</c:if>>Russia</option>
-        <option value="sa"<c:if test="${relaycountries_country[0] eq 'sa'}"> selected</c:if>>Saudi Arabia</option>
-        <option value="kr"<c:if test="${relaycountries_country[0] eq 'kr'}"> selected</c:if>>South Korea</option>
-        <option value="sd"<c:if test="${relaycountries_country[0] eq 'sd'}"> selected</c:if>>Sudan</option>
-        <option value="se"<c:if test="${relaycountries_country[0] eq 'se'}"> selected</c:if>>Sweden</option>
-        <option value="sy"<c:if test="${relaycountries_country[0] eq 'sy'}"> selected</c:if>>Syria</option>
-        <option value="tn"<c:if test="${relaycountries_country[0] eq 'tn'}"> selected</c:if>>Tunisia</option>
-        <option value="tm"<c:if test="${relaycountries_country[0] eq 'tm'}"> selected</c:if>>Turkmenistan</option>
-        <option value="ae"<c:if test="${relaycountries_country[0] eq 'ae'}"> selected</c:if>>U.A.E.</option>
-        <option value="gb"<c:if test="${relaycountries_country[0] eq 'gb'}"> selected</c:if>>U.K.</option>
-        <option value="us"<c:if test="${relaycountries_country[0] eq 'us'}"> selected</c:if>>U.S.A.</option>
-        <option value="uz"<c:if test="${relaycountries_country[0] eq 'uz'}"> selected</c:if>>Uzbekistan</option>
-        <option value="vn"<c:if test="${relaycountries_country[0] eq 'vn'}"> selected</c:if>>Vietnam</option>
-        <option value="ye"<c:if test="${relaycountries_country[0] eq 'ye'}"> selected</c:if>>Yemen</option>
+        <c:forEach var="country" items="${countries}" >
+          <option value="${country[0]}"<c:if test="${relaycountries_country[0] eq country[0]}"> selected</c:if>>${country[1]}</option>
+        </c:forEach>
       </select>
     </p><p>
       Resolution: <select name="dpi">
diff --git a/web/WEB-INF/users.jsp b/web/WEB-INF/users.jsp
index 9d88e96..7ea45a5 100644
--- a/web/WEB-INF/users.jsp
+++ b/web/WEB-INF/users.jsp
@@ -37,48 +37,9 @@ based on the requests seen by a few dozen directory mirrors.</p>
     </p><p>
       Source: <select name="country">
         <option value="all"<c:if test="${direct_users_country[0] eq 'all'}"> selected</c:if>>All users</option>
-        <option value="dz"<c:if test="${direct_users_country[0] eq 'dz'}"> selected</c:if>>Algeria</option>
-        <option value="au"<c:if test="${direct_users_country[0] eq 'au'}"> selected</c:if>>Australia</option>
-        <option value="bh"<c:if test="${direct_users_country[0] eq 'bh'}"> selected</c:if>>Bahrain</option>
-        <option value="br"<c:if test="${direct_users_country[0] eq 'br'}"> selected</c:if>>Brazil</option>
-        <option value="mm"<c:if test="${direct_users_country[0] eq 'mm'}"> selected</c:if>>Burma</option>
-        <option value="ca"<c:if test="${direct_users_country[0] eq 'ca'}"> selected</c:if>>Canada</option>
-        <option value="cn"<c:if test="${direct_users_country[0] eq 'cn'}"> selected</c:if>>China</option>
-        <option value="cu"<c:if test="${direct_users_country[0] eq 'cu'}"> selected</c:if>>Cuba</option>
-        <option value="dj"<c:if test="${direct_users_country[0] eq 'dj'}"> selected</c:if>>Djibouti</option>
-        <option value="eg"<c:if test="${direct_users_country[0] eq 'eg'}"> selected</c:if>>Egypt</option>
-        <option value="et"<c:if test="${direct_users_country[0] eq 'et'}"> selected</c:if>>Ethiopia</option>
-        <option value="fr"<c:if test="${direct_users_country[0] eq 'fr'}"> selected</c:if>>France</option>
-        <option value="de"<c:if test="${direct_users_country[0] eq 'de'}"> selected</c:if>>Germany</option>
-        <option value="ir"<c:if test="${direct_users_country[0] eq 'ir'}"> selected</c:if>>Iran</option>
-        <option value="iq"<c:if test="${direct_users_country[0] eq 'iq'}"> selected</c:if>>Iraq</option>
-        <option value="il"<c:if test="${direct_users_country[0] eq 'il'}"> selected</c:if>>Israel</option>
-        <option value="it"<c:if test="${direct_users_country[0] eq 'it'}"> selected</c:if>>Italy</option>
-        <option value="jp"<c:if test="${direct_users_country[0] eq 'jp'}"> selected</c:if>>Japan</option>
-        <option value="jo"<c:if test="${direct_users_country[0] eq 'jo'}"> selected</c:if>>Jordan</option>
-        <option value="kw"<c:if test="${direct_users_country[0] eq 'kw'}"> selected</c:if>>Kuwait</option>
-        <option value="lb"<c:if test="${direct_users_country[0] eq 'lb'}"> selected</c:if>>Lebanon</option>
-        <option value="ly"<c:if test="${direct_users_country[0] eq 'ly'}"> selected</c:if>>Libya</option>
-        <option value="ma"<c:if test="${direct_users_country[0] eq 'ma'}"> selected</c:if>>Morocco</option>
-        <option value="kp"<c:if test="${direct_users_country[0] eq 'kp'}"> selected</c:if>>North Korea</option>
-        <option value="om"<c:if test="${direct_users_country[0] eq 'om'}"> selected</c:if>>Oman</option>
-        <option value="ps"<c:if test="${direct_users_country[0] eq 'ps'}"> selected</c:if>>Palestinian territories</option>
-        <option value="pl"<c:if test="${direct_users_country[0] eq 'pl'}"> selected</c:if>>Poland</option>
-        <option value="qa"<c:if test="${direct_users_country[0] eq 'qa'}"> selected</c:if>>Qatar</option>
-        <option value="ru"<c:if test="${direct_users_country[0] eq 'ru'}"> selected</c:if>>Russia</option>
-        <option value="sa"<c:if test="${direct_users_country[0] eq 'sa'}"> selected</c:if>>Saudi Arabia</option>
-        <option value="kr"<c:if test="${direct_users_country[0] eq 'kr'}"> selected</c:if>>South Korea</option>
-        <option value="sd"<c:if test="${direct_users_country[0] eq 'sd'}"> selected</c:if>>Sudan</option>
-        <option value="se"<c:if test="${direct_users_country[0] eq 'se'}"> selected</c:if>>Sweden</option>
-        <option value="sy"<c:if test="${direct_users_country[0] eq 'sy'}"> selected</c:if>>Syria</option>
-        <option value="tn"<c:if test="${direct_users_country[0] eq 'tn'}"> selected</c:if>>Tunisia</option>
-        <option value="tm"<c:if test="${direct_users_country[0] eq 'tm'}"> selected</c:if>>Turkmenistan</option>
-        <option value="ae"<c:if test="${direct_users_country[0] eq 'ae'}"> selected</c:if>>U.A.E.</option>
-        <option value="gb"<c:if test="${direct_users_country[0] eq 'gb'}"> selected</c:if>>U.K.</option>
-        <option value="us"<c:if test="${direct_users_country[0] eq 'us'}"> selected</c:if>>U.S.A.</option>
-        <option value="uz"<c:if test="${direct_users_country[0] eq 'uz'}"> selected</c:if>>Uzbekistan</option>
-        <option value="vn"<c:if test="${direct_users_country[0] eq 'vn'}"> selected</c:if>>Vietnam</option>
-        <option value="ye"<c:if test="${direct_users_country[0] eq 'ye'}"> selected</c:if>>Yemen</option>
+        <c:forEach var="country" items="${countries}" >
+          <option value="${country[0]}"<c:if test="${direct_users_country[0] eq country[0]}"> selected</c:if>>${country[1]}</option>
+        </c:forEach>
       </select>
     </p><p>
       Resolution: <select name="dpi">
@@ -120,48 +81,9 @@ by a few hundred bridges.</p>
     </p><p>
       Source: <select name="country">
         <option value="all"<c:if test="${bridge_users_country[0] eq 'all'}"> selected</c:if>>All users</option>
-        <option value="dz"<c:if test="${bridge_users_country[0] eq 'dz'}"> selected</c:if>>Algeria</option>
-        <option value="au"<c:if test="${bridge_users_country[0] eq 'au'}"> selected</c:if>>Australia</option>
-        <option value="bh"<c:if test="${bridge_users_country[0] eq 'bh'}"> selected</c:if>>Bahrain</option>
-        <option value="br"<c:if test="${bridge_users_country[0] eq 'br'}"> selected</c:if>>Brazil</option>
-        <option value="mm"<c:if test="${bridge_users_country[0] eq 'mm'}"> selected</c:if>>Burma</option>
-        <option value="ca"<c:if test="${bridge_users_country[0] eq 'ca'}"> selected</c:if>>Canada</option>
-        <option value="cn"<c:if test="${bridge_users_country[0] eq 'cn'}"> selected</c:if>>China</option>
-        <option value="cu"<c:if test="${bridge_users_country[0] eq 'cu'}"> selected</c:if>>Cuba</option>
-        <option value="dj"<c:if test="${bridge_users_country[0] eq 'dj'}"> selected</c:if>>Djibouti</option>
-        <option value="eg"<c:if test="${bridge_users_country[0] eq 'eg'}"> selected</c:if>>Egypt</option>
-        <option value="et"<c:if test="${bridge_users_country[0] eq 'et'}"> selected</c:if>>Ethiopia</option>
-        <option value="fr"<c:if test="${bridge_users_country[0] eq 'fr'}"> selected</c:if>>France</option>
-        <option value="de"<c:if test="${bridge_users_country[0] eq 'de'}"> selected</c:if>>Germany</option>
-        <option value="ir"<c:if test="${bridge_users_country[0] eq 'ir'}"> selected</c:if>>Iran</option>
-        <option value="iq"<c:if test="${bridge_users_country[0] eq 'iq'}"> selected</c:if>>Iraq</option>
-        <option value="il"<c:if test="${bridge_users_country[0] eq 'il'}"> selected</c:if>>Israel</option>
-        <option value="it"<c:if test="${bridge_users_country[0] eq 'it'}"> selected</c:if>>Italy</option>
-        <option value="jp"<c:if test="${bridge_users_country[0] eq 'jp'}"> selected</c:if>>Japan</option>
-        <option value="jo"<c:if test="${bridge_users_country[0] eq 'jo'}"> selected</c:if>>Jordan</option>
-        <option value="kw"<c:if test="${bridge_users_country[0] eq 'kw'}"> selected</c:if>>Kuwait</option>
-        <option value="lb"<c:if test="${bridge_users_country[0] eq 'lb'}"> selected</c:if>>Lebanon</option>
-        <option value="ly"<c:if test="${bridge_users_country[0] eq 'ly'}"> selected</c:if>>Libya</option>
-        <option value="ma"<c:if test="${bridge_users_country[0] eq 'ma'}"> selected</c:if>>Morocco</option>
-        <option value="kp"<c:if test="${bridge_users_country[0] eq 'kp'}"> selected</c:if>>North Korea</option>
-        <option value="om"<c:if test="${bridge_users_country[0] eq 'om'}"> selected</c:if>>Oman</option>
-        <option value="ps"<c:if test="${bridge_users_country[0] eq 'ps'}"> selected</c:if>>Palestinian territories</option>
-        <option value="pl"<c:if test="${bridge_users_country[0] eq 'pl'}"> selected</c:if>>Poland</option>
-        <option value="qa"<c:if test="${bridge_users_country[0] eq 'qa'}"> selected</c:if>>Qatar</option>
-        <option value="ru"<c:if test="${bridge_users_country[0] eq 'ru'}"> selected</c:if>>Russia</option>
-        <option value="sa"<c:if test="${bridge_users_country[0] eq 'sa'}"> selected</c:if>>Saudi Arabia</option>
-        <option value="kr"<c:if test="${bridge_users_country[0] eq 'kr'}"> selected</c:if>>South Korea</option>
-        <option value="sd"<c:if test="${bridge_users_country[0] eq 'sd'}"> selected</c:if>>Sudan</option>
-        <option value="se"<c:if test="${bridge_users_country[0] eq 'se'}"> selected</c:if>>Sweden</option>
-        <option value="sy"<c:if test="${bridge_users_country[0] eq 'sy'}"> selected</c:if>>Syria</option>
-        <option value="tn"<c:if test="${bridge_users_country[0] eq 'tn'}"> selected</c:if>>Tunisia</option>
-        <option value="tm"<c:if test="${bridge_users_country[0] eq 'tm'}"> selected</c:if>>Turkmenistan</option>
-        <option value="ae"<c:if test="${bridge_users_country[0] eq 'ae'}"> selected</c:if>>U.A.E.</option>
-        <option value="gb"<c:if test="${bridge_users_country[0] eq 'gb'}"> selected</c:if>>U.K.</option>
-        <option value="us"<c:if test="${bridge_users_country[0] eq 'us'}"> selected</c:if>>U.S.A.</option>
-        <option value="uz"<c:if test="${bridge_users_country[0] eq 'uz'}"> selected</c:if>>Uzbekistan</option>
-        <option value="vn"<c:if test="${bridge_users_country[0] eq 'vn'}"> selected</c:if>>Vietnam</option>
-        <option value="ye"<c:if test="${bridge_users_country[0] eq 'ye'}"> selected</c:if>>Yemen</option>
+        <c:forEach var="country" items="${countries}" >
+          <option value="${country[0]}"<c:if test="${bridge_users_country[0] eq country[0]}"> selected</c:if>>${country[1]}</option>
+        </c:forEach>
       </select>
     </p><p>
       Resolution: <select name="dpi">



More information about the tor-commits mailing list