tor-commits
Threads by month
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
July 2014
- 25 participants
- 1534 discussions
[onionoo/master] Move front-end parts of NodeStatus to SummaryDocument.
by karsten@torproject.org 22 Jul '14
by karsten@torproject.org 22 Jul '14
22 Jul '14
commit ab7f4ee58825a7980579e6cd4e334ee373b29047
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Tue Jul 22 13:53:42 2014 +0200
Move front-end parts of NodeStatus to SummaryDocument.
The NodeStatus class was seriously overloaded:
1. NodeDetailsStatusUpdater uses the list of NodeStatus instances as
input to its GeoIP and rDNS look-up operations and to calculate
path-selection probabilities.
2. DetailsDocumentWriter uses fields from NodeStatus instances (some of
them being stored persistently, some only kept in memory) to write
part of DetailsDocument instances.
3. NodeIndexer obtains all relevant data to populate the search index
from NodeStatus instances.
4. ResponseBuilder uses NodeStatus instances to produce summary documents
on-the-fly.
As first step to reduce this complexity, let's copy the parts used for 3
and 4 to a currently unused class, SummaryDocument, and use that class in
NodeIndexer and ResponseBuilder. It makes sense to combine those two
purposes for performance reasons. Parts 1 and 2 will be simplified in
later commits.
---
src/org/torproject/onionoo/DocumentStore.java | 235 +++++++++++++-------
src/org/torproject/onionoo/Main.java | 4 +-
.../onionoo/NodeDetailsStatusUpdater.java | 2 +-
src/org/torproject/onionoo/NodeIndexer.java | 38 ++--
src/org/torproject/onionoo/RequestHandler.java | 65 +++---
src/org/torproject/onionoo/ResponseBuilder.java | 52 ++---
src/org/torproject/onionoo/SummaryDocument.java | 195 +++++++++++++++-
.../torproject/onionoo/SummaryDocumentWriter.java | 87 ++++++++
.../org/torproject/onionoo/DummyDocumentStore.java | 2 +-
.../torproject/onionoo/ResourceServletTest.java | 107 +++++----
10 files changed, 569 insertions(+), 218 deletions(-)
diff --git a/src/org/torproject/onionoo/DocumentStore.java b/src/org/torproject/onionoo/DocumentStore.java
index e3bf618..434ecb6 100644
--- a/src/org/torproject/onionoo/DocumentStore.java
+++ b/src/org/torproject/onionoo/DocumentStore.java
@@ -11,7 +11,9 @@ import java.io.FileInputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.SortedSet;
@@ -43,46 +45,39 @@ public class DocumentStore {
this.time = ApplicationFactory.getTime();
}
- private boolean listedArchivedNodeStatuses = false,
- listedCurrentNodeStatuses = false;
-
private long listOperations = 0L, listedFiles = 0L, storedFiles = 0L,
storedBytes = 0L, retrievedFiles = 0L, retrievedBytes = 0L,
removedFiles = 0L;
- /* Node statuses are cached in memory, as opposed to all other document
- * types. This cache is initialized when listing NodeStatus documents,
- * either including or excluding archived node statuses. Later retrieve
- * operations depend on which NodeStatus documents were listed. */
+ /* Node statuses and summary documents are cached in memory, as opposed
+ * to all other document types. These caches are initialized when first
+ * accessing or modifying a NodeStatus or SummaryDocument document,
+ * respectively. */
private SortedMap<String, NodeStatus> cachedNodeStatuses;
+ private SortedMap<String, SummaryDocument> cachedSummaryDocuments;
public <T extends Document> SortedSet<String> list(
- Class<T> documentType, boolean includeArchive) {
+ Class<T> documentType) {
if (documentType.equals(NodeStatus.class)) {
- return this.listNodeStatuses(includeArchive);
+ return this.listNodeStatuses();
+ } else if (documentType.equals(SummaryDocument.class)) {
+ return this.listSummaryDocuments();
} else {
return this.listDocumentFiles(documentType);
}
}
- private SortedSet<String> listNodeStatuses(boolean includeArchive) {
- if ((includeArchive && listedCurrentNodeStatuses) ||
- (!includeArchive && listedArchivedNodeStatuses)) {
- System.err.println("Listing node statuses is only permitted "
- + "including the archive or excluding the archive, but not "
- + "both. Returning empty list.");
- return new TreeSet<String>();
- }
+ private SortedSet<String> listNodeStatuses() {
if (this.cachedNodeStatuses == null) {
- this.cacheNodeStatuses(includeArchive);
+ this.cacheNodeStatuses();
}
return new TreeSet<String>(this.cachedNodeStatuses.keySet());
}
- private void cacheNodeStatuses(boolean includeArchive) {
+ private void cacheNodeStatuses() {
SortedMap<String, NodeStatus> parsedNodeStatuses =
new TreeMap<String, NodeStatus>();
- File directory = includeArchive ? this.statusDir : this.outDir;
+ File directory = this.statusDir;
if (directory != null) {
File summaryFile = new File(directory, "summary");
if (summaryFile.exists()) {
@@ -109,14 +104,56 @@ public class DocumentStore {
}
}
}
- if (includeArchive) {
- this.listedArchivedNodeStatuses = true;
- } else {
- this.listedCurrentNodeStatuses = true;
- }
this.cachedNodeStatuses = parsedNodeStatuses;
}
+ private SortedSet<String> listSummaryDocuments() {
+ if (this.cachedSummaryDocuments == null) {
+ this.cacheSummaryDocuments();
+ }
+ return new TreeSet<String>(this.cachedSummaryDocuments.keySet());
+ }
+
+ private void cacheSummaryDocuments() {
+ SortedMap<String, SummaryDocument> parsedSummaryDocuments =
+ new TreeMap<String, SummaryDocument>();
+ File directory = this.outDir;
+ if (directory != null) {
+ File summaryFile = new File(directory, "summary");
+ if (summaryFile.exists()) {
+ String line = null;
+ try {
+ Gson gson = new Gson();
+ BufferedReader br = new BufferedReader(new FileReader(
+ summaryFile));
+ while ((line = br.readLine()) != null) {
+ if (line.length() == 0) {
+ continue;
+ }
+ SummaryDocument summaryDocument = gson.fromJson(line,
+ SummaryDocument.class);
+ if (summaryDocument != null) {
+ parsedSummaryDocuments.put(summaryDocument.getFingerprint(),
+ summaryDocument);
+ }
+ }
+ br.close();
+ this.listedFiles += parsedSummaryDocuments.size();
+ this.listOperations++;
+ } catch (IOException e) {
+ System.err.println("Could not read file '"
+ + summaryFile.getAbsolutePath() + "'.");
+ e.printStackTrace();
+ } catch (JsonParseException e) {
+ System.err.println("Could not parse summary document '" + line
+ + "' in file '" + summaryFile.getAbsolutePath() + "'.");
+ e.printStackTrace();
+ }
+ }
+ }
+ this.cachedSummaryDocuments = parsedSummaryDocuments;
+ }
+
private <T extends Document> SortedSet<String> listDocumentFiles(
Class<T> documentType) {
SortedSet<String> fingerprints = new TreeSet<String>();
@@ -178,6 +215,9 @@ public class DocumentStore {
String fingerprint) {
if (document instanceof NodeStatus) {
return this.storeNodeStatus((NodeStatus) document, fingerprint);
+ } else if (document instanceof SummaryDocument) {
+ return this.storeSummaryDocument((SummaryDocument) document,
+ fingerprint);
} else {
return this.storeDocumentFile(document, fingerprint);
}
@@ -186,12 +226,21 @@ public class DocumentStore {
private <T extends Document> boolean storeNodeStatus(
NodeStatus nodeStatus, String fingerprint) {
if (this.cachedNodeStatuses == null) {
- this.cacheNodeStatuses(true);
+ this.cacheNodeStatuses();
}
this.cachedNodeStatuses.put(fingerprint, nodeStatus);
return true;
}
+ private <T extends Document> boolean storeSummaryDocument(
+ SummaryDocument summaryDocument, String fingerprint) {
+ if (this.cachedSummaryDocuments == null) {
+ this.cacheSummaryDocuments();
+ }
+ this.cachedSummaryDocuments.put(fingerprint, summaryDocument);
+ return true;
+ }
+
private <T extends Document> boolean storeDocumentFile(T document,
String fingerprint) {
File documentFile = this.getDocumentFile(document.getClass(),
@@ -270,6 +319,8 @@ public class DocumentStore {
boolean parse, String fingerprint) {
if (documentType.equals(NodeStatus.class)) {
return documentType.cast(this.retrieveNodeStatus(fingerprint));
+ } else if (documentType.equals(SummaryDocument.class)) {
+ return documentType.cast(this.retrieveSummaryDocument(fingerprint));
} else {
return this.retrieveDocumentFile(documentType, parse, fingerprint);
}
@@ -277,12 +328,17 @@ public class DocumentStore {
private NodeStatus retrieveNodeStatus(String fingerprint) {
if (this.cachedNodeStatuses == null) {
- this.cacheNodeStatuses(true);
+ this.cacheNodeStatuses();
}
- if (this.cachedNodeStatuses.containsKey(fingerprint)) {
- return this.cachedNodeStatuses.get(fingerprint);
- } else if (this.listedArchivedNodeStatuses) {
- return null;
+ return this.cachedNodeStatuses.get(fingerprint);
+ }
+
+ private SummaryDocument retrieveSummaryDocument(String fingerprint) {
+ if (this.cachedSummaryDocuments == null) {
+ this.cacheSummaryDocuments();
+ }
+ if (this.cachedSummaryDocuments.containsKey(fingerprint)) {
+ return this.cachedSummaryDocuments.get(fingerprint);
}
/* TODO This is an evil hack to support looking up relays or bridges
* that haven't been running for a week without having to load
@@ -294,39 +350,35 @@ public class DocumentStore {
return null;
}
boolean isRelay = detailsDocument.getHashedFingerprint() == null;
+ boolean running = false;
String nickname = detailsDocument.getNickname();
- String address = null, countryCode = null, hostName = null,
- defaultPolicy = null, portList = null, aSNumber = null,
- contact = null;
- SortedSet<String> orAddressesAndPorts = new TreeSet<String>();
+ List<String> addresses = new ArrayList<String>();
+ String countryCode = null, aSNumber = null, contact = null;
for (String orAddressAndPort : detailsDocument.getOrAddresses()) {
- if (address == null) {
- if (!orAddressAndPort.contains(":")) {
- return null;
- }
- address = orAddressAndPort.substring(0,
- orAddressAndPort.lastIndexOf(":"));
- } else {
- orAddressesAndPorts.add(orAddressAndPort);
+ if (!orAddressAndPort.contains(":")) {
+ return null;
+ }
+ String orAddress = orAddressAndPort.substring(0,
+ orAddressAndPort.lastIndexOf(":"));
+ if (!addresses.contains(orAddress)) {
+ addresses.add(orAddress);
}
}
- SortedSet<String> exitAddresses = new TreeSet<String>();
if (detailsDocument.getExitAddresses() != null) {
- exitAddresses.addAll(detailsDocument.getExitAddresses());
+ for (String exitAddress : detailsDocument.getExitAddresses()) {
+ if (!addresses.contains(exitAddress)) {
+ addresses.add(exitAddress);
+ }
+ }
}
SortedSet<String> relayFlags = new TreeSet<String>(), family = null;
long lastSeenMillis = -1L, consensusWeight = -1L,
- lastRdnsLookup = -1L, firstSeenMillis = -1L,
- lastChangedAddresses = -1L;
- int orPort = 0, dirPort = 0;
- Boolean recommendedVersion = null;
- NodeStatus nodeStatus = new NodeStatus(isRelay, nickname, fingerprint,
- address, orAddressesAndPorts, exitAddresses, lastSeenMillis,
- orPort, dirPort, relayFlags, consensusWeight, countryCode,
- hostName, lastRdnsLookup, defaultPolicy, portList,
- firstSeenMillis, lastChangedAddresses, aSNumber, contact,
- recommendedVersion, family);
- return nodeStatus;
+ firstSeenMillis = -1L;
+ SummaryDocument summaryDocument = new SummaryDocument(isRelay,
+ nickname, fingerprint, addresses, lastSeenMillis, running,
+ relayFlags, consensusWeight, countryCode, firstSeenMillis,
+ aSNumber, contact, family);
+ return summaryDocument;
}
private <T extends Document> T retrieveDocumentFile(
@@ -455,6 +507,8 @@ public class DocumentStore {
String fingerprint) {
if (documentType.equals(NodeStatus.class)) {
return this.removeNodeStatus(fingerprint);
+ } else if (documentType.equals(SummaryDocument.class)) {
+ return this.removeSummaryDocument(fingerprint);
} else {
return this.removeDocumentFile(documentType, fingerprint);
}
@@ -462,11 +516,18 @@ public class DocumentStore {
private boolean removeNodeStatus(String fingerprint) {
if (this.cachedNodeStatuses == null) {
- this.cacheNodeStatuses(true);
+ this.cacheNodeStatuses();
}
return this.cachedNodeStatuses.remove(fingerprint) != null;
}
+ private boolean removeSummaryDocument(String fingerprint) {
+ if (this.cachedSummaryDocuments == null) {
+ this.cacheSummaryDocuments();
+ }
+ return this.cachedSummaryDocuments.remove(fingerprint) != null;
+ }
+
private <T extends Document> boolean removeDocumentFile(
Class<T> documentType, String fingerprint) {
File documentFile = this.getDocumentFile(documentType, fingerprint);
@@ -550,18 +611,20 @@ public class DocumentStore {
* containing current time. It's important to write the update file
* now, not earlier, because the front-end should not read new node
* statuses until all details, bandwidths, and weights are ready. */
- if (this.listedArchivedNodeStatuses) {
- this.writeNodeStatuses(false);
- this.writeNodeStatuses(true);
- this.writeUpdateStatus();
- } else if (this.listedCurrentNodeStatuses) {
- this.writeNodeStatuses(false);
+ if (this.cachedNodeStatuses != null ||
+ this.cachedSummaryDocuments != null) {
+ if (this.cachedNodeStatuses != null) {
+ this.writeNodeStatuses();
+ }
+ if (this.cachedSummaryDocuments != null) {
+ this.writeSummaryDocuments();
+ }
this.writeUpdateStatus();
}
}
- private void writeNodeStatuses(boolean includeArchive) {
- File directory = includeArchive ? this.statusDir : this.outDir;
+ private void writeNodeStatuses() {
+ File directory = this.statusDir;
if (directory == null) {
return;
}
@@ -569,21 +632,8 @@ public class DocumentStore {
SortedMap<String, NodeStatus>
cachedRelays = new TreeMap<String, NodeStatus>(),
cachedBridges = new TreeMap<String, NodeStatus>();
- long cutoff = 0L;
- if (!includeArchive) {
- long maxLastSeenMillis = 0L;
- for (NodeStatus node : this.cachedNodeStatuses.values()) {
- if (node.getLastSeenMillis() > maxLastSeenMillis) {
- maxLastSeenMillis = node.getLastSeenMillis();
- }
- }
- cutoff = maxLastSeenMillis - DateTimeHelper.ONE_WEEK;
- }
for (Map.Entry<String, NodeStatus> e :
this.cachedNodeStatuses.entrySet()) {
- if (e.getValue().getLastSeenMillis() < cutoff) {
- continue;
- }
if (e.getValue().isRelay()) {
cachedRelays.put(e.getKey(), e.getValue());
} else {
@@ -624,6 +674,35 @@ public class DocumentStore {
}
}
+ private void writeSummaryDocuments() {
+ StringBuilder sb = new StringBuilder();
+ Gson gson = new Gson();
+ for (SummaryDocument summaryDocument :
+ this.cachedSummaryDocuments.values()) {
+ String line = gson.toJson(summaryDocument);
+ if (line != null) {
+ sb.append(line + "\n");
+ } else {
+ System.err.println("Could not serialize relay summary document '"
+ + summaryDocument.getFingerprint() + "'");
+ }
+ }
+ String documentString = sb.toString();
+ File summaryFile = new File(this.outDir, "summary");
+ try {
+ summaryFile.getParentFile().mkdirs();
+ BufferedWriter bw = new BufferedWriter(new FileWriter(summaryFile));
+ bw.write(documentString);
+ bw.close();
+ this.storedFiles++;
+ this.storedBytes += documentString.length();
+ } catch (IOException e) {
+ System.err.println("Could not write file '"
+ + summaryFile.getAbsolutePath() + "'.");
+ e.printStackTrace();
+ }
+ }
+
private void writeUpdateStatus() {
if (this.outDir == null) {
return;
diff --git a/src/org/torproject/onionoo/Main.java b/src/org/torproject/onionoo/Main.java
index 0ae12e4..e9afe2f 100644
--- a/src/org/torproject/onionoo/Main.java
+++ b/src/org/torproject/onionoo/Main.java
@@ -45,6 +45,8 @@ public class Main {
StatusUpdater[] sus = new StatusUpdater[] { ndsu, bsu, wsu, csu,
usu };
+ SummaryDocumentWriter sdw = new SummaryDocumentWriter();
+ Logger.printStatusTime("Initialized summary document writer");
DetailsDocumentWriter ddw = new DetailsDocumentWriter();
Logger.printStatusTime("Initialized details document writer");
BandwidthDocumentWriter bdw = new BandwidthDocumentWriter();
@@ -55,7 +57,7 @@ public class Main {
Logger.printStatusTime("Initialized clients document writer");
UptimeDocumentWriter udw = new UptimeDocumentWriter();
Logger.printStatusTime("Initialized uptime document writer");
- DocumentWriter[] dws = new DocumentWriter[] { ddw, bdw, wdw, cdw,
+ DocumentWriter[] dws = new DocumentWriter[] { sdw, ddw, bdw, wdw, cdw,
udw };
Logger.printStatus("Downloading descriptors.");
diff --git a/src/org/torproject/onionoo/NodeDetailsStatusUpdater.java b/src/org/torproject/onionoo/NodeDetailsStatusUpdater.java
index e898638..a1149a5 100644
--- a/src/org/torproject/onionoo/NodeDetailsStatusUpdater.java
+++ b/src/org/torproject/onionoo/NodeDetailsStatusUpdater.java
@@ -310,7 +310,7 @@ public class NodeDetailsStatusUpdater implements DescriptorListener,
private void readStatusSummary() {
SortedSet<String> fingerprints = this.documentStore.list(
- NodeStatus.class, true);
+ NodeStatus.class);
for (String fingerprint : fingerprints) {
NodeStatus node = this.documentStore.retrieve(NodeStatus.class,
true, fingerprint);
diff --git a/src/org/torproject/onionoo/NodeIndexer.java b/src/org/torproject/onionoo/NodeIndexer.java
index 8a04afb..d24284e 100644
--- a/src/org/torproject/onionoo/NodeIndexer.java
+++ b/src/org/torproject/onionoo/NodeIndexer.java
@@ -44,21 +44,21 @@ class NodeIndex {
}
- private Map<String, NodeStatus> relayFingerprintSummaryLines;
+ private Map<String, SummaryDocument> relayFingerprintSummaryLines;
public void setRelayFingerprintSummaryLines(
- Map<String, NodeStatus> relayFingerprintSummaryLines) {
+ Map<String, SummaryDocument> relayFingerprintSummaryLines) {
this.relayFingerprintSummaryLines = relayFingerprintSummaryLines;
}
- public Map<String, NodeStatus> getRelayFingerprintSummaryLines() {
+ public Map<String, SummaryDocument> getRelayFingerprintSummaryLines() {
return this.relayFingerprintSummaryLines;
}
- private Map<String, NodeStatus> bridgeFingerprintSummaryLines;
+ private Map<String, SummaryDocument> bridgeFingerprintSummaryLines;
public void setBridgeFingerprintSummaryLines(
- Map<String, NodeStatus> bridgeFingerprintSummaryLines) {
+ Map<String, SummaryDocument> bridgeFingerprintSummaryLines) {
this.bridgeFingerprintSummaryLines = bridgeFingerprintSummaryLines;
}
- public Map<String, NodeStatus> getBridgeFingerprintSummaryLines() {
+ public Map<String, SummaryDocument> getBridgeFingerprintSummaryLines() {
return this.bridgeFingerprintSummaryLines;
}
@@ -239,11 +239,11 @@ public class NodeIndexer implements ServletContextListener, Runnable {
}
}
List<String> newRelaysByConsensusWeight = new ArrayList<String>();
- Map<String, NodeStatus>
+ Map<String, SummaryDocument>
newRelayFingerprintSummaryLines =
- new HashMap<String, NodeStatus>(),
+ new HashMap<String, SummaryDocument>(),
newBridgeFingerprintSummaryLines =
- new HashMap<String, NodeStatus>();
+ new HashMap<String, SummaryDocument>();
Map<String, Set<String>>
newRelaysByCountryCode = new HashMap<String, Set<String>>(),
newRelaysByASNumber = new HashMap<String, Set<String>>(),
@@ -256,14 +256,14 @@ public class NodeIndexer implements ServletContextListener, Runnable {
newBridgesByFirstSeenDays = new TreeMap<Integer, Set<String>>(),
newRelaysByLastSeenDays = new TreeMap<Integer, Set<String>>(),
newBridgesByLastSeenDays = new TreeMap<Integer, Set<String>>();
- Set<NodeStatus> currentRelays = new HashSet<NodeStatus>(),
- currentBridges = new HashSet<NodeStatus>();
- SortedSet<String> fingerprints = documentStore.list(NodeStatus.class,
- false);
+ Set<SummaryDocument> currentRelays = new HashSet<SummaryDocument>(),
+ currentBridges = new HashSet<SummaryDocument>();
+ SortedSet<String> fingerprints = documentStore.list(
+ SummaryDocument.class);
long relaysLastValidAfterMillis = 0L, bridgesLastPublishedMillis = 0L;
for (String fingerprint : fingerprints) {
- NodeStatus node = documentStore.retrieve(NodeStatus.class, true,
- fingerprint);
+ SummaryDocument node = documentStore.retrieve(SummaryDocument.class,
+ true, fingerprint);
if (node.isRelay()) {
relaysLastValidAfterMillis = Math.max(
relaysLastValidAfterMillis, node.getLastSeenMillis());
@@ -276,12 +276,10 @@ public class NodeIndexer implements ServletContextListener, Runnable {
}
Time time = ApplicationFactory.getTime();
List<String> orderRelaysByConsensusWeight = new ArrayList<String>();
- for (NodeStatus entry : currentRelays) {
+ for (SummaryDocument entry : currentRelays) {
String fingerprint = entry.getFingerprint().toUpperCase();
String hashedFingerprint = entry.getHashedFingerprint().
toUpperCase();
- entry.setRunning(entry.getLastSeenMillis() ==
- relaysLastValidAfterMillis);
newRelayFingerprintSummaryLines.put(fingerprint, entry);
newRelayFingerprintSummaryLines.put(hashedFingerprint, entry);
long consensusWeight = entry.getConsensusWeight();
@@ -360,12 +358,10 @@ public class NodeIndexer implements ServletContextListener, Runnable {
}
e.getValue().retainAll(inMutualFamilyRelation);
}
- for (NodeStatus entry : currentBridges) {
+ for (SummaryDocument entry : currentBridges) {
String hashedFingerprint = entry.getFingerprint().toUpperCase();
String hashedHashedFingerprint = entry.getHashedFingerprint().
toUpperCase();
- entry.setRunning(entry.getRelayFlags().contains("Running") &&
- entry.getLastSeenMillis() == bridgesLastPublishedMillis);
newBridgeFingerprintSummaryLines.put(hashedFingerprint, entry);
newBridgeFingerprintSummaryLines.put(hashedHashedFingerprint,
entry);
diff --git a/src/org/torproject/onionoo/RequestHandler.java b/src/org/torproject/onionoo/RequestHandler.java
index 66559e6..39a66e1 100644
--- a/src/org/torproject/onionoo/RequestHandler.java
+++ b/src/org/torproject/onionoo/RequestHandler.java
@@ -10,6 +10,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
+import java.util.SortedSet;
public class RequestHandler {
@@ -109,11 +110,11 @@ public class RequestHandler {
this.family = family;
}
- private Map<String, NodeStatus> filteredRelays =
- new HashMap<String, NodeStatus>();
+ private Map<String, SummaryDocument> filteredRelays =
+ new HashMap<String, SummaryDocument>();
- private Map<String, NodeStatus> filteredBridges =
- new HashMap<String, NodeStatus>();
+ private Map<String, SummaryDocument> filteredBridges =
+ new HashMap<String, SummaryDocument>();
public void handleRequest() {
this.filteredRelays.putAll(
@@ -164,8 +165,9 @@ public class RequestHandler {
}
boolean runningRequested = this.running.equals("true");
Set<String> removeRelays = new HashSet<String>();
- for (Map.Entry<String, NodeStatus> e : filteredRelays.entrySet()) {
- if (e.getValue().getRunning() != runningRequested) {
+ for (Map.Entry<String, SummaryDocument> e :
+ filteredRelays.entrySet()) {
+ if (e.getValue().isRunning() != runningRequested) {
removeRelays.add(e.getKey());
}
}
@@ -173,8 +175,9 @@ public class RequestHandler {
this.filteredRelays.remove(fingerprint);
}
Set<String> removeBridges = new HashSet<String>();
- for (Map.Entry<String, NodeStatus> e : filteredBridges.entrySet()) {
- if (e.getValue().getRunning() != runningRequested) {
+ for (Map.Entry<String, SummaryDocument> e :
+ filteredBridges.entrySet()) {
+ if (e.getValue().isRunning() != runningRequested) {
removeBridges.add(e.getKey());
}
}
@@ -194,9 +197,10 @@ public class RequestHandler {
private void filterBySearchTerm(String searchTerm) {
Set<String> removeRelays = new HashSet<String>();
- for (Map.Entry<String, NodeStatus> e : filteredRelays.entrySet()) {
+ for (Map.Entry<String, SummaryDocument> e :
+ filteredRelays.entrySet()) {
String fingerprint = e.getKey();
- NodeStatus entry = e.getValue();
+ SummaryDocument entry = e.getValue();
boolean lineMatches = false;
String nickname = entry.getNickname() != null ?
entry.getNickname().toLowerCase() : "unnamed";
@@ -214,14 +218,7 @@ public class RequestHandler {
/* Non-$-prefixed fingerprint matches. */
lineMatches = true;
} else {
- List<String> addresses = new ArrayList<String>();
- addresses.add(entry.getAddress().toLowerCase());
- for (String orAddress : entry.getOrAddresses()) {
- addresses.add(orAddress.toLowerCase());
- }
- for (String exitAddress : entry.getExitAddresses()) {
- addresses.add(exitAddress.toLowerCase());
- }
+ List<String> addresses = entry.getAddresses();
for (String address : addresses) {
if (address.startsWith(searchTerm.toLowerCase())) {
/* Address matches. */
@@ -238,9 +235,10 @@ public class RequestHandler {
this.filteredRelays.remove(fingerprint);
}
Set<String> removeBridges = new HashSet<String>();
- for (Map.Entry<String, NodeStatus> e : filteredBridges.entrySet()) {
+ for (Map.Entry<String, SummaryDocument> e :
+ filteredBridges.entrySet()) {
String hashedFingerprint = e.getKey();
- NodeStatus entry = e.getValue();
+ SummaryDocument entry = e.getValue();
boolean lineMatches = false;
String nickname = entry.getNickname() != null ?
entry.getNickname().toLowerCase() : "unnamed";
@@ -272,12 +270,12 @@ public class RequestHandler {
return;
}
String fingerprint = this.lookup;
- NodeStatus relayLine = this.filteredRelays.get(fingerprint);
+ SummaryDocument relayLine = this.filteredRelays.get(fingerprint);
this.filteredRelays.clear();
if (relayLine != null) {
this.filteredRelays.put(fingerprint, relayLine);
}
- NodeStatus bridgeLine = this.filteredBridges.get(fingerprint);
+ SummaryDocument bridgeLine = this.filteredBridges.get(fingerprint);
this.filteredBridges.clear();
if (bridgeLine != null) {
this.filteredBridges.put(fingerprint, bridgeLine);
@@ -291,8 +289,8 @@ public class RequestHandler {
this.filteredRelays.clear();
this.filteredBridges.clear();
String fingerprint = this.fingerprint;
- NodeStatus entry = this.documentStore.retrieve(NodeStatus.class, true,
- fingerprint);
+ SummaryDocument entry = this.documentStore.retrieve(
+ SummaryDocument.class, true, fingerprint);
if (entry != null) {
if (entry.isRelay()) {
this.filteredRelays.put(fingerprint, entry);
@@ -409,7 +407,8 @@ public class RequestHandler {
this.nodeIndex.getBridgesByLastSeenDays(), this.lastSeenDays);
}
- private void filterNodesByDays(Map<String, NodeStatus> filteredNodes,
+ private void filterNodesByDays(
+ Map<String, SummaryDocument> filteredNodes,
SortedMap<Integer, Set<String>> nodesByDays, int[] days) {
Set<String> removeNodes = new HashSet<String>();
for (Set<String> nodes : nodesByDays.headMap(days[0]).values()) {
@@ -483,14 +482,14 @@ public class RequestHandler {
this.orderedRelays.add(this.filteredRelays.remove(relay));
}
}
- Set<NodeStatus> uniqueBridges = new HashSet<NodeStatus>(
+ Set<SummaryDocument> uniqueBridges = new HashSet<SummaryDocument>(
this.filteredBridges.values());
this.orderedBridges.addAll(uniqueBridges);
} else {
- Set<NodeStatus> uniqueRelays = new HashSet<NodeStatus>(
+ Set<SummaryDocument> uniqueRelays = new HashSet<SummaryDocument>(
this.filteredRelays.values());
this.orderedRelays.addAll(uniqueRelays);
- Set<NodeStatus> uniqueBridges = new HashSet<NodeStatus>(
+ Set<SummaryDocument> uniqueBridges = new HashSet<SummaryDocument>(
this.filteredBridges.values());
this.orderedBridges.addAll(uniqueBridges);
}
@@ -528,13 +527,15 @@ public class RequestHandler {
}
}
- private List<NodeStatus> orderedRelays = new ArrayList<NodeStatus>();
- public List<NodeStatus> getOrderedRelays() {
+ private List<SummaryDocument> orderedRelays =
+ new ArrayList<SummaryDocument>();
+ public List<SummaryDocument> getOrderedRelays() {
return this.orderedRelays;
}
- private List<NodeStatus> orderedBridges = new ArrayList<NodeStatus>();
- public List<NodeStatus> getOrderedBridges() {
+ private List<SummaryDocument> orderedBridges =
+ new ArrayList<SummaryDocument>();
+ public List<SummaryDocument> getOrderedBridges() {
return this.orderedBridges;
}
diff --git a/src/org/torproject/onionoo/ResponseBuilder.java b/src/org/torproject/onionoo/ResponseBuilder.java
index 77c4b6c..2086ea8 100644
--- a/src/org/torproject/onionoo/ResponseBuilder.java
+++ b/src/org/torproject/onionoo/ResponseBuilder.java
@@ -32,13 +32,15 @@ public class ResponseBuilder {
this.bridgesPublishedString = bridgesPublishedString;
}
- private List<NodeStatus> orderedRelays = new ArrayList<NodeStatus>();
- public void setOrderedRelays(List<NodeStatus> orderedRelays) {
+ private List<SummaryDocument> orderedRelays =
+ new ArrayList<SummaryDocument>();
+ public void setOrderedRelays(List<SummaryDocument> orderedRelays) {
this.orderedRelays = orderedRelays;
}
- private List<NodeStatus> orderedBridges = new ArrayList<NodeStatus>();
- public void setOrderedBridges(List<NodeStatus> orderedBridges) {
+ private List<SummaryDocument> orderedBridges =
+ new ArrayList<SummaryDocument>();
+ public void setOrderedBridges(List<SummaryDocument> orderedBridges) {
this.orderedBridges = orderedBridges;
}
@@ -53,11 +55,11 @@ public class ResponseBuilder {
writeBridges(orderedBridges, pw);
}
- private void writeRelays(List<NodeStatus> relays, PrintWriter pw) {
+ private void writeRelays(List<SummaryDocument> relays, PrintWriter pw) {
pw.write("{\"relays_published\":\"" + relaysPublishedString
+ "\",\n\"relays\":[");
int written = 0;
- for (NodeStatus entry : relays) {
+ for (SummaryDocument entry : relays) {
String lines = this.formatNodeStatus(entry);
if (lines.length() > 0) {
pw.print((written++ > 0 ? ",\n" : "\n") + lines);
@@ -66,11 +68,12 @@ public class ResponseBuilder {
pw.print("\n],\n");
}
- private void writeBridges(List<NodeStatus> bridges, PrintWriter pw) {
+ private void writeBridges(List<SummaryDocument> bridges,
+ PrintWriter pw) {
pw.write("\"bridges_published\":\"" + bridgesPublishedString
+ "\",\n\"bridges\":[");
int written = 0;
- for (NodeStatus entry : bridges) {
+ for (SummaryDocument entry : bridges) {
String lines = this.formatNodeStatus(entry);
if (lines.length() > 0) {
pw.print((written++ > 0 ? ",\n" : "\n") + lines);
@@ -79,7 +82,7 @@ public class ResponseBuilder {
pw.print("\n]}\n");
}
- private String formatNodeStatus(NodeStatus entry) {
+ private String formatNodeStatus(SummaryDocument entry) {
if (this.resourceType == null) {
return "";
} else if (this.resourceType.equals("summary")) {
@@ -99,26 +102,17 @@ public class ResponseBuilder {
}
}
- private String writeSummaryLine(NodeStatus entry) {
+ private String writeSummaryLine(SummaryDocument entry) {
return entry.isRelay() ? writeRelaySummaryLine(entry)
: writeBridgeSummaryLine(entry);
}
- private String writeRelaySummaryLine(NodeStatus entry) {
+ private String writeRelaySummaryLine(SummaryDocument entry) {
String nickname = !entry.getNickname().equals("Unnamed") ?
entry.getNickname() : null;
String fingerprint = entry.getFingerprint();
- String running = entry.getRunning() ? "true" : "false";
- List<String> addresses = new ArrayList<String>();
- addresses.add(entry.getAddress());
- for (String orAddress : entry.getOrAddresses()) {
- addresses.add(orAddress);
- }
- for (String exitAddress : entry.getExitAddresses()) {
- if (!addresses.contains(exitAddress)) {
- addresses.add(exitAddress);
- }
- }
+ String running = entry.isRunning() ? "true" : "false";
+ List<String> addresses = entry.getAddresses();
StringBuilder addressesBuilder = new StringBuilder();
int written = 0;
for (String address : addresses) {
@@ -130,17 +124,17 @@ public class ResponseBuilder {
fingerprint, addressesBuilder.toString(), running);
}
- private String writeBridgeSummaryLine(NodeStatus entry) {
+ private String writeBridgeSummaryLine(SummaryDocument entry) {
String nickname = !entry.getNickname().equals("Unnamed") ?
entry.getNickname() : null;
String hashedFingerprint = entry.getFingerprint();
- String running = entry.getRunning() ? "true" : "false";
+ String running = entry.isRunning() ? "true" : "false";
return String.format("{%s\"h\":\"%s\",\"r\":%s}",
(nickname == null ? "" : "\"n\":\"" + nickname + "\","),
hashedFingerprint, running);
}
- private String writeDetailsLines(NodeStatus entry) {
+ private String writeDetailsLines(SummaryDocument entry) {
String fingerprint = entry.getFingerprint();
if (this.fields != null) {
/* TODO Maybe there's a more elegant way (more maintainable, more
@@ -267,7 +261,7 @@ public class ResponseBuilder {
}
}
- private String writeBandwidthLines(NodeStatus entry) {
+ private String writeBandwidthLines(SummaryDocument entry) {
String fingerprint = entry.getFingerprint();
BandwidthDocument bandwidthDocument = this.documentStore.retrieve(
BandwidthDocument.class, false, fingerprint);
@@ -279,7 +273,7 @@ public class ResponseBuilder {
}
}
- private String writeWeightsLines(NodeStatus entry) {
+ private String writeWeightsLines(SummaryDocument entry) {
String fingerprint = entry.getFingerprint();
WeightsDocument weightsDocument = this.documentStore.retrieve(
WeightsDocument.class, false, fingerprint);
@@ -291,7 +285,7 @@ public class ResponseBuilder {
}
}
- private String writeClientsLines(NodeStatus entry) {
+ private String writeClientsLines(SummaryDocument entry) {
String fingerprint = entry.getFingerprint();
ClientsDocument clientsDocument = this.documentStore.retrieve(
ClientsDocument.class, false, fingerprint);
@@ -303,7 +297,7 @@ public class ResponseBuilder {
}
}
- private String writeUptimeLines(NodeStatus entry) {
+ private String writeUptimeLines(SummaryDocument entry) {
String fingerprint = entry.getFingerprint();
UptimeDocument uptimeDocument = this.documentStore.retrieve(
UptimeDocument.class, false, fingerprint);
diff --git a/src/org/torproject/onionoo/SummaryDocument.java b/src/org/torproject/onionoo/SummaryDocument.java
index 63862a2..3c0f700 100644
--- a/src/org/torproject/onionoo/SummaryDocument.java
+++ b/src/org/torproject/onionoo/SummaryDocument.java
@@ -1,8 +1,201 @@
-/* Copyright 2013 The Tor Project
+/* Copyright 2013--2014 The Tor Project
* See LICENSE for licensing information */
package org.torproject.onionoo;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import java.util.regex.Pattern;
+
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
+import org.apache.commons.codec.digest.DigestUtils;
+
class SummaryDocument extends Document {
+ private boolean t;
+ public void setRelay(boolean isRelay) {
+ this.t = isRelay;
+ }
+ public boolean isRelay() {
+ return this.t;
+ }
+
+ private String f;
+ public void setFingerprint(String fingerprint) {
+ if (fingerprint != null) {
+ Pattern fingerprintPattern = Pattern.compile("^[0-9a-fA-F]{40}$");
+ if (!fingerprintPattern.matcher(fingerprint).matches()) {
+ throw new IllegalArgumentException("Fingerprint '" + fingerprint
+ + "' is not a valid fingerprint.");
+ }
+ }
+ this.f = fingerprint;
+ }
+ public String getFingerprint() {
+ return this.f;
+ }
+
+ public String getHashedFingerprint() {
+ String hashedFingerprint = null;
+ if (this.f != null) {
+ try {
+ hashedFingerprint = DigestUtils.shaHex(Hex.decodeHex(
+ this.f.toCharArray())).toUpperCase();
+ } catch (DecoderException e) {
+ /* Format tested in setFingerprint(). */
+ }
+ }
+ return hashedFingerprint;
+ }
+
+ private String n;
+ public void setNickname(String nickname) {
+ if (nickname == null || nickname.equals("Unnamed")) {
+ this.n = null;
+ } else {
+ this.n = nickname;
+ }
+ }
+ public String getNickname() {
+ return this.n == null ? "Unnamed" : this.n;
+ }
+
+ private String[] ad;
+ public void setAddresses(List<String> addresses) {
+ this.ad = this.collectionToStringArray(addresses);
+ }
+ public List<String> getAddresses() {
+ return this.stringArrayToList(this.ad);
+ }
+
+ private String[] collectionToStringArray(
+ Collection<String> collection) {
+ String[] stringArray = null;
+ if (collection != null && !collection.isEmpty()) {
+ stringArray = new String[collection.size()];
+ int i = 0;
+ for (String string : collection) {
+ stringArray[i++] = string;
+ }
+ }
+ return stringArray;
+ }
+ private List<String> stringArrayToList(String[] stringArray) {
+ List<String> list;
+ if (stringArray == null) {
+ list = new ArrayList<String>();
+ } else {
+ list = Arrays.asList(stringArray);
+ }
+ return list;
+ }
+ private SortedSet<String> stringArrayToSortedSet(String[] stringArray) {
+ SortedSet<String> sortedSet = new TreeSet<String>();
+ if (stringArray != null) {
+ sortedSet.addAll(Arrays.asList(stringArray));
+ }
+ return sortedSet;
+ }
+
+ private String cc;
+ public void setCountryCode(String countryCode) {
+ this.cc = countryCode;
+ }
+ public String getCountryCode() {
+ return this.cc;
+ }
+
+ private String as;
+ public void setASNumber(String aSNumber) {
+ this.as = aSNumber;
+ }
+ public String getASNumber() {
+ return this.as;
+ }
+
+ private String fs;
+ public void setFirstSeenMillis(long firstSeenMillis) {
+ this.fs = DateTimeHelper.format(firstSeenMillis);
+ }
+ public long getFirstSeenMillis() {
+ return DateTimeHelper.parse(this.fs);
+ }
+
+ private String ls;
+ public void setLastSeenMillis(long lastSeenMillis) {
+ this.ls = DateTimeHelper.format(lastSeenMillis);
+ }
+ public long getLastSeenMillis() {
+ return DateTimeHelper.parse(this.ls);
+ }
+
+ private String[] rf;
+ public void setRelayFlags(SortedSet<String> relayFlags) {
+ this.rf = this.collectionToStringArray(relayFlags);
+ }
+ public SortedSet<String> getRelayFlags() {
+ return this.stringArrayToSortedSet(this.rf);
+ }
+
+ private long cw;
+ public void setConsensusWeight(long consensusWeight) {
+ this.cw = consensusWeight;
+ }
+ public long getConsensusWeight() {
+ return this.cw;
+ }
+
+ private boolean r;
+ public void setRunning(boolean isRunning) {
+ this.r = isRunning;
+ }
+ public boolean isRunning() {
+ return this.r;
+ }
+
+ private String c;
+ public void setContact(String contact) {
+ if (contact != null && contact.length() == 0) {
+ this.c = null;
+ } else {
+ this.c = contact;
+ }
+ }
+ public String getContact() {
+ return this.c;
+ }
+
+ private String[] ff;
+ public void setFamilyFingerprints(
+ SortedSet<String> familyFingerprints) {
+ this.ff = this.collectionToStringArray(familyFingerprints);
+ }
+ public SortedSet<String> getFamilyFingerprints() {
+ return this.stringArrayToSortedSet(this.ff);
+ }
+
+ public SummaryDocument(boolean isRelay, String nickname,
+ String fingerprint, List<String> addresses, long lastSeenMillis,
+ boolean running, SortedSet<String> relayFlags, long consensusWeight,
+ String countryCode, long firstSeenMillis, String aSNumber,
+ String contact, SortedSet<String> familyFingerprints) {
+ this.setRelay(isRelay);
+ this.setNickname(nickname);
+ this.setFingerprint(fingerprint);
+ this.setAddresses(addresses);
+ this.setLastSeenMillis(lastSeenMillis);
+ this.setRunning(running);
+ this.setRelayFlags(relayFlags);
+ this.setConsensusWeight(consensusWeight);
+ this.setCountryCode(countryCode);
+ this.setFirstSeenMillis(firstSeenMillis);
+ this.setASNumber(aSNumber);
+ this.setContact(contact);
+ this.setFamilyFingerprints(familyFingerprints);
+ }
}
diff --git a/src/org/torproject/onionoo/SummaryDocumentWriter.java b/src/org/torproject/onionoo/SummaryDocumentWriter.java
new file mode 100644
index 0000000..7b257f5
--- /dev/null
+++ b/src/org/torproject/onionoo/SummaryDocumentWriter.java
@@ -0,0 +1,87 @@
+/* Copyright 2014 The Tor Project
+ * See LICENSE for licensing information */
+package org.torproject.onionoo;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedSet;
+
+public class SummaryDocumentWriter implements DocumentWriter {
+
+ private DocumentStore documentStore;
+
+ public SummaryDocumentWriter() {
+ this.documentStore = ApplicationFactory.getDocumentStore();
+ }
+
+ private int writtenDocuments = 0, deletedDocuments = 0;
+
+ public void writeDocuments() {
+ long maxLastSeenMillis = 0L;
+ for (String fingerprint : this.documentStore.list(NodeStatus.class)) {
+ NodeStatus nodeStatus = this.documentStore.retrieve(
+ NodeStatus.class, true, fingerprint);
+ if (nodeStatus != null &&
+ nodeStatus.getLastSeenMillis() > maxLastSeenMillis) {
+ maxLastSeenMillis = nodeStatus.getLastSeenMillis();
+ }
+ }
+ long cutoff = maxLastSeenMillis - DateTimeHelper.ONE_WEEK;
+ for (String fingerprint : this.documentStore.list(NodeStatus.class)) {
+ NodeStatus nodeStatus = this.documentStore.retrieve(
+ NodeStatus.class,
+ true, fingerprint);
+ if (nodeStatus == null) {
+ continue;
+ }
+ if (nodeStatus.getLastSeenMillis() < cutoff) {
+ if (this.documentStore.remove(SummaryDocument.class,
+ fingerprint)) {
+ this.deletedDocuments++;
+ }
+ continue;
+ }
+ boolean isRelay = nodeStatus.isRelay();
+ String nickname = nodeStatus.getNickname();
+ List<String> addresses = new ArrayList<String>();
+ addresses.add(nodeStatus.getAddress());
+ for (String orAddress : nodeStatus.getOrAddresses()) {
+ if (!addresses.contains(orAddress)) {
+ addresses.add(orAddress);
+ }
+ }
+ for (String exitAddress : nodeStatus.getExitAddresses()) {
+ if (!addresses.contains(exitAddress)) {
+ addresses.add(exitAddress);
+ }
+ }
+ long lastSeenMillis = nodeStatus.getLastSeenMillis();
+ boolean running = nodeStatus.getRunning();
+ SortedSet<String> relayFlags = nodeStatus.getRelayFlags();
+ long consensusWeight = nodeStatus.getConsensusWeight();
+ String countryCode = nodeStatus.getCountryCode();
+ long firstSeenMillis = nodeStatus.getFirstSeenMillis();
+ String aSNumber = nodeStatus.getASNumber();
+ String contact = nodeStatus.getContact();
+ SortedSet<String> familyFingerprints =
+ nodeStatus.getFamilyFingerprints();
+ SummaryDocument summaryDocument = new SummaryDocument(isRelay,
+ nickname, fingerprint, addresses, lastSeenMillis, running,
+ relayFlags, consensusWeight, countryCode, firstSeenMillis,
+ aSNumber, contact, familyFingerprints);
+ if (this.documentStore.store(summaryDocument, fingerprint)) {
+ this.writtenDocuments++;
+ };
+ }
+ Logger.printStatusTime("Wrote summary document files");
+ }
+
+ public String getStatsString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append(" " + Logger.formatDecimalNumber(this.writtenDocuments)
+ + " summary document files written\n");
+ sb.append(" " + Logger.formatDecimalNumber(this.deletedDocuments)
+ + " summary document files deleted\n");
+ return sb.toString();
+ }
+}
diff --git a/test/org/torproject/onionoo/DummyDocumentStore.java b/test/org/torproject/onionoo/DummyDocumentStore.java
index 6969b8f..5a5905b 100644
--- a/test/org/torproject/onionoo/DummyDocumentStore.java
+++ b/test/org/torproject/onionoo/DummyDocumentStore.java
@@ -51,7 +51,7 @@ public class DummyDocumentStore extends DocumentStore {
}
public <T extends Document> SortedSet<String> list(
- Class<T> documentType, boolean includeArchive) {
+ Class<T> documentType) {
this.performedListOperations++;
return new TreeSet<String>(this.getStoredDocumentsByClass(
documentType).keySet());
diff --git a/test/org/torproject/onionoo/ResourceServletTest.java b/test/org/torproject/onionoo/ResourceServletTest.java
index f8d3281..e482f82 100644
--- a/test/org/torproject/onionoo/ResourceServletTest.java
+++ b/test/org/torproject/onionoo/ResourceServletTest.java
@@ -31,7 +31,8 @@ import com.google.gson.Gson;
* which tests servlet specifics. */
public class ResourceServletTest {
- private SortedMap<String, NodeStatus> relays, bridges;
+ private SortedMap<String, org.torproject.onionoo.SummaryDocument>
+ relays, bridges;
private long currentTimeMillis = DateTimeHelper.parse(
"2013-04-24 12:22:22");
@@ -100,77 +101,73 @@ public class ResourceServletTest {
@Before
public void createSampleRelaysAndBridges() {
- NodeStatus relayTorkaZ = new NodeStatus(true, "TorkaZ",
- "000C5F55BD4814B917CC474BD537F1A3B33CCE2A", "62.216.201.221",
- new TreeSet<String>(), new TreeSet<String>(Arrays.asList(
- new String[] { "62.216.201.222", "62.216.201.223" })),
- DateTimeHelper.parse("2013-04-19 05:00:00"), 9001, 0,
- new TreeSet<String>(Arrays.asList(new String[] { "Running",
- "Valid" })), 20L, "de", null, -1L, "reject", "1-65535",
- DateTimeHelper.parse("2013-04-18 05:00:00"),
- DateTimeHelper.parse("2013-04-19 05:00:00"), "AS8767",
+ org.torproject.onionoo.SummaryDocument relayTorkaZ =
+ new org.torproject.onionoo.SummaryDocument(true, "TorkaZ",
+ "000C5F55BD4814B917CC474BD537F1A3B33CCE2A", Arrays.asList(
+ new String[] { "62.216.201.221", "62.216.201.222",
+ "62.216.201.223" }), DateTimeHelper.parse("2013-04-19 05:00:00"),
+ false, new TreeSet<String>(Arrays.asList(new String[] { "Running",
+ "Valid" })), 20L, "de",
+ DateTimeHelper.parse("2013-04-18 05:00:00"), "AS8767",
"torkaz <klaus dot zufall at gmx dot de> "
- + "<fb-token:np5_g_83jmf=>", null, new TreeSet<String>(
- Arrays.asList(new String[] {
- "001C13B3A55A71B977CA65EC85539D79C653A3FC",
+ + "<fb-token:np5_g_83jmf=>", new TreeSet<String>(Arrays.asList(
+ new String[] { "001C13B3A55A71B977CA65EC85539D79C653A3FC",
"0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B" })));
- NodeStatus relayFerrari458 = new NodeStatus(true, "Ferrari458",
- "001C13B3A55A71B977CA65EC85539D79C653A3FC", "68.38.171.200",
- new TreeSet<String>(Arrays.asList(new String[] {
- "[2001:4f8:3:2e::51]:9001" })), new TreeSet<String>(),
- DateTimeHelper.parse("2013-04-24 12:00:00"), 9001, 9030,
+ org.torproject.onionoo.SummaryDocument relayFerrari458 =
+ new org.torproject.onionoo.SummaryDocument(true, "Ferrari458",
+ "001C13B3A55A71B977CA65EC85539D79C653A3FC", Arrays.asList(
+ new String[] { "68.38.171.200", "[2001:4f8:3:2e::51]" }),
+ DateTimeHelper.parse("2013-04-24 12:00:00"), true,
new TreeSet<String>(Arrays.asList(new String[] { "Fast", "Named",
"Running", "V2Dir", "Valid" })), 1140L, "us",
- "c-68-38-171-200.hsd1.pa.comcast.net", 1366805763009L, "reject",
- "1-65535", DateTimeHelper.parse("2013-02-12 16:00:00"),
- DateTimeHelper.parse("2013-02-26 18:00:00"), "AS7922", null, null,
+ DateTimeHelper.parse("2013-02-12 16:00:00"), "AS7922", null,
new TreeSet<String>(Arrays.asList(new String[] {
"000C5F55BD4814B917CC474BD537F1A3B33CCE2A" })));
- relayFerrari458.setRunning(true);
- NodeStatus relayTimMayTribute = new NodeStatus(true, "TimMayTribute",
- "0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B", "89.69.68.246",
- new TreeSet<String>(), new TreeSet<String>(),
- DateTimeHelper.parse("2013-04-22 20:00:00"), 9001, 9030,
+ org.torproject.onionoo.SummaryDocument relayTimMayTribute =
+ new org.torproject.onionoo.SummaryDocument(true, "TimMayTribute",
+ "0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B", Arrays.asList(
+ new String[] { "89.69.68.246" }),
+ DateTimeHelper.parse("2013-04-22 20:00:00"), false,
new TreeSet<String>(Arrays.asList(new String[] { "Fast",
- "Running", "Unnamed", "V2Dir", "Valid" })), 63L, "a1", null, -1L,
- "reject", "1-65535", DateTimeHelper.parse("2013-04-16 18:00:00"),
+ "Running", "Unnamed", "V2Dir", "Valid" })), 63L, "a1",
DateTimeHelper.parse("2013-04-16 18:00:00"), "AS6830",
"1024D/51E2A1C7 steven j. murdoch "
+ "<tor+steven.murdoch(a)cl.cam.ac.uk> <fb-token:5sr_k_zs2wm=>",
- null, new TreeSet<String>());
- NodeStatus bridgeec2bridgercc7f31fe = new NodeStatus(false,
+ new TreeSet<String>());
+ org.torproject.onionoo.SummaryDocument bridgeec2bridgercc7f31fe =
+ new org.torproject.onionoo.SummaryDocument(false,
"ec2bridgercc7f31fe", "0000831B236DFF73D409AD17B40E2A728A53994F",
- "10.199.7.176", new TreeSet<String>(), new TreeSet<String>(),
- DateTimeHelper.parse("2013-04-21 18:07:03"), 443, 0,
+ Arrays.asList(new String[] { "10.199.7.176" }),
+ DateTimeHelper.parse("2013-04-21 18:07:03"), false,
new TreeSet<String>(Arrays.asList(new String[] { "Valid" })), -1L,
- "??", null, -1L, null, null,
- DateTimeHelper.parse("2013-04-20 15:37:04"), -1L, null, null,
- null, null);
- NodeStatus bridgeUnnamed = new NodeStatus(false, "Unnamed",
- "0002D9BDBBC230BD9C78FF502A16E0033EF87E0C", "10.0.52.84",
- new TreeSet<String>(), new TreeSet<String>(),
- DateTimeHelper.parse("2013-04-20 17:37:04"), 443, 0,
+ null, DateTimeHelper.parse("2013-04-20 15:37:04"), null, null,
+ null);
+ org.torproject.onionoo.SummaryDocument bridgeUnnamed =
+ new org.torproject.onionoo.SummaryDocument(false, "Unnamed",
+ "0002D9BDBBC230BD9C78FF502A16E0033EF87E0C", Arrays.asList(
+ new String[] { "10.0.52.84" }),
+ DateTimeHelper.parse("2013-04-20 17:37:04"), false,
new TreeSet<String>(Arrays.asList(new String[] { "Valid" })), -1L,
- "??", null, -1L, null, null,
- DateTimeHelper.parse("2013-04-14 07:07:05"), -1L, null, null,
- null, null);
- NodeStatus bridgegummy = new NodeStatus(false, "gummy",
- "1FEDE50ED8DBA1DD9F9165F78C8131E4A44AB756", "10.63.169.98",
- new TreeSet<String>(), new TreeSet<String>(),
- DateTimeHelper.parse("2013-04-24 01:07:04"), 9001, 0,
+ null, DateTimeHelper.parse("2013-04-14 07:07:05"), null, null,
+ null);
+ org.torproject.onionoo.SummaryDocument bridgegummy =
+ new org.torproject.onionoo.SummaryDocument(false, "gummy",
+ "1FEDE50ED8DBA1DD9F9165F78C8131E4A44AB756", Arrays.asList(
+ new String[] { "10.63.169.98" }),
+ DateTimeHelper.parse("2013-04-24 01:07:04"), true,
new TreeSet<String>(Arrays.asList(new String[] { "Running",
- "Valid" })), -1L, "??", null, -1L, null, null,
- DateTimeHelper.parse("2013-01-16 21:07:04"), -1L, null, null,
- null, null);
- bridgegummy.setRunning(true);
- this.relays = new TreeMap<String, NodeStatus>();
+ "Valid" })), -1L, null,
+ DateTimeHelper.parse("2013-01-16 21:07:04"), null, null, null);
+ this.relays =
+ new TreeMap<String, org.torproject.onionoo.SummaryDocument>();
this.relays.put("000C5F55BD4814B917CC474BD537F1A3B33CCE2A",
relayTorkaZ);
this.relays.put("001C13B3A55A71B977CA65EC85539D79C653A3FC",
relayFerrari458);
this.relays.put("0025C136C1F3A9EEFE2AE3F918F03BFA21B5070B",
relayTimMayTribute);
- this.bridges = new TreeMap<String, NodeStatus>();
+ this.bridges =
+ new TreeMap<String, org.torproject.onionoo.SummaryDocument>();
this.bridges.put("0000831B236DFF73D409AD17B40E2A728A53994F",
bridgeec2bridgercc7f31fe);
this.bridges.put("0002D9BDBBC230BD9C78FF502A16E0033EF87E0C",
@@ -203,10 +200,12 @@ public class ResourceServletTest {
updateStatus.setDocumentString(String.valueOf(
this.currentTimeMillis));
documentStore.addDocument(updateStatus, null);
- for (Map.Entry<String, NodeStatus> e : relays.entrySet()) {
+ for (Map.Entry<String, org.torproject.onionoo.SummaryDocument> e :
+ this.relays.entrySet()) {
documentStore.addDocument(e.getValue(), e.getKey());
}
- for (Map.Entry<String, NodeStatus> e : bridges.entrySet()) {
+ for (Map.Entry<String, org.torproject.onionoo.SummaryDocument> e :
+ this.bridges.entrySet()) {
documentStore.addDocument(e.getValue(), e.getKey());
}
ApplicationFactory.setDocumentStore(documentStore);
1
0
22 Jul '14
commit 3d303e20f58d3e523e0fa97ba1095db6ca05bd4c
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Jul 22 15:15:06 2014 +0000
Update translations for gettor
---
sk_SK/gettor.po | 34 +++++++++++++++++-----------------
1 file changed, 17 insertions(+), 17 deletions(-)
diff --git a/sk_SK/gettor.po b/sk_SK/gettor.po
index 6e52d97..3c352ac 100644
--- a/sk_SK/gettor.po
+++ b/sk_SK/gettor.po
@@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: The Tor Project\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-01-19 13:40+0100\n"
-"PO-Revision-Date: 2014-07-22 14:43+0000\n"
+"PO-Revision-Date: 2014-07-22 15:14+0000\n"
"Last-Translator: once <matejbacik(a)gmail.com>\n"
"Language-Team: Slovak (Slovakia) (http://www.transifex.com/projects/p/torproject/language/sk_SK/)\n"
"MIME-Version: 1.0\n"
@@ -20,11 +20,11 @@ msgstr ""
#: lib/gettor/i18n.py:27
msgid "Hello, This is the \"GetTor\" robot."
-msgstr ""
+msgstr "Ahoj, tu je \"GetTor\" robot."
#: lib/gettor/i18n.py:29
msgid "Thank you for your request."
-msgstr ""
+msgstr "Ďakujeme za vašu požiadavku."
#: lib/gettor/i18n.py:31
msgid ""
@@ -38,14 +38,14 @@ msgid ""
"We only process requests from email services that support \"DKIM\",\n"
"which is an email feature that lets us verify that the address in the\n"
"\"From\" line is actually the one who sent the mail."
-msgstr ""
+msgstr "Spracovávame iba požiadavky z e-mailových služieb podporujúcich \"DKIM\",\nčo je funkcia e-mailu, ktorá nám umožní overiť, že adresa v riadku \"Od\" je\nskutočne od toho, kto odoslal e-mail."
#: lib/gettor/i18n.py:39
msgid ""
"(We apologize if you didn't ask for this mail. Since your email is from\n"
"a service that doesn't use DKIM, we're sending a short explanation,\n"
"and then we'll ignore this email address for the next day or so.)"
-msgstr ""
+msgstr "(Ospravedlňujeme sa, ak ste o tento e-mail nežiadal vy. Keďže váš\nposkytovateľ e-mailu nepoužíva DKIM, posielame krátke vysvetlenie.\nTúto e-mailovú adresu budeme asi jeden deň ignorovať.)"
#: lib/gettor/i18n.py:43 lib/gettor/i18n.py:135
msgid ""
@@ -100,7 +100,7 @@ msgstr ""
#: lib/gettor/i18n.py:76
msgid " List of supported locales:"
-msgstr ""
+msgstr "Zoznam podporovaných lokalizácií:"
#: lib/gettor/i18n.py:78
msgid "Here is a list of all available languages:"
@@ -151,13 +151,13 @@ msgstr ""
msgid ""
"Sending this text in an email to GetTor will cause it to send you \n"
"the Tor Browser Bundle in a number of 1,4MB attachments."
-msgstr ""
+msgstr "Odoslanie tohoto textu v e-maile na adresu GetTor spôsobí, že vám\nz neho príde Tor Browser Bundle v niekoľkých prílohách s veľkosťou 1,4MB."
#: lib/gettor/i18n.py:110
msgid ""
"After having received all parts, you need to re-assemble them to \n"
"one package again. This is done as follows:"
-msgstr ""
+msgstr "Potom, čo obržíte všetky časti, je potrebné, aby ste ich znova spojili\ndo jedného balíčka. To vykonáte nasledovne:"
#: lib/gettor/i18n.py:113
msgid "1.) Save all received attachments into one folder on your disk."
@@ -188,11 +188,11 @@ msgid ""
"5.) After unpacking is finished, you should find a newly created \n"
"\".exe\" file in your destination folder. Simply doubleclick\n"
"that and Tor Browser Bundle should start within a few seconds."
-msgstr ""
+msgstr "5.) Potom, čo rozbaľovanie skončilo, nájdite novovytvorený \".exe\" súbor\nv cieľovom priečinku. Stačí dvojklikom otvoriť tento súbor\na Tor Browser Bundle by sa mal v priebehu niekoľkých sekúnd spustiť."
#: lib/gettor/i18n.py:130
msgid "6.) That's it. You're done. Thanks for using Tor and have fun!"
-msgstr ""
+msgstr "6.) Hotovo. To je všetko. Ďakujeme, že používate Tor a prajeme veľa zábavy!"
#: lib/gettor/i18n.py:132
msgid ""
@@ -436,11 +436,11 @@ msgstr ""
#: lib/gettor/i18n.py:272
msgid "What is Tor?"
-msgstr ""
+msgstr "Čo je Tor?"
#: lib/gettor/i18n.py:274
msgid "The name \"Tor\" can refer to several different components."
-msgstr ""
+msgstr "Názov \"Tor\" sa môže viazať na niekoľko rôznych komponentov."
#: lib/gettor/i18n.py:276
msgid ""
@@ -457,7 +457,7 @@ msgstr ""
#: lib/gettor/i18n.py:286
msgid "What is the Tor Browser Bundle?"
-msgstr ""
+msgstr "Čo je Tor Browser Bundle?"
#: lib/gettor/i18n.py:288
msgid ""
@@ -468,7 +468,7 @@ msgstr ""
#: lib/gettor/i18n.py:292
msgid "What package should I request?"
-msgstr ""
+msgstr "Ktorý balíček by som si mal vyžiadať?"
#: lib/gettor/i18n.py:294
msgid ""
@@ -480,15 +480,15 @@ msgstr ""
#: lib/gettor/i18n.py:299
msgid "How do I extract the file(s) you sent me?"
-msgstr ""
+msgstr "Ako rozbalím súbor(y), ktoré ste mi poslali?"
#: lib/gettor/i18n.py:301
msgid "QUESTION:"
-msgstr ""
+msgstr "OTÁZKA:"
#: lib/gettor/i18n.py:303
msgid "ANSWER:"
-msgstr ""
+msgstr "ODPOVEĎ:"
#: lib/gettor/i18n.py:305
#, python-format
1
0
22 Jul '14
commit a9a94d55a7b134684d54382fc598425b3aa5a939
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Jul 22 14:45:07 2014 +0000
Update translations for gettor
---
sk_SK/gettor.po | 503 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 503 insertions(+)
diff --git a/sk_SK/gettor.po b/sk_SK/gettor.po
new file mode 100644
index 0000000..6e52d97
--- /dev/null
+++ b/sk_SK/gettor.po
@@ -0,0 +1,503 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+#
+# Translators:
+# once <matejbacik(a)gmail.com>, 2014
+msgid ""
+msgstr ""
+"Project-Id-Version: The Tor Project\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2013-01-19 13:40+0100\n"
+"PO-Revision-Date: 2014-07-22 14:43+0000\n"
+"Last-Translator: once <matejbacik(a)gmail.com>\n"
+"Language-Team: Slovak (Slovakia) (http://www.transifex.com/projects/p/torproject/language/sk_SK/)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Language: sk_SK\n"
+"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
+
+#: lib/gettor/i18n.py:27
+msgid "Hello, This is the \"GetTor\" robot."
+msgstr ""
+
+#: lib/gettor/i18n.py:29
+msgid "Thank you for your request."
+msgstr ""
+
+#: lib/gettor/i18n.py:31
+msgid ""
+"Unfortunately, we won't answer you at this address. You should make\n"
+"an account with GMAIL.COM, YAHOO.COM or YAHOO.CN and send the mail from\n"
+"one of those."
+msgstr ""
+
+#: lib/gettor/i18n.py:35
+msgid ""
+"We only process requests from email services that support \"DKIM\",\n"
+"which is an email feature that lets us verify that the address in the\n"
+"\"From\" line is actually the one who sent the mail."
+msgstr ""
+
+#: lib/gettor/i18n.py:39
+msgid ""
+"(We apologize if you didn't ask for this mail. Since your email is from\n"
+"a service that doesn't use DKIM, we're sending a short explanation,\n"
+"and then we'll ignore this email address for the next day or so.)"
+msgstr ""
+
+#: lib/gettor/i18n.py:43 lib/gettor/i18n.py:135
+msgid ""
+"If you have any questions or it doesn't work, you can contact a\n"
+"human at this support email address: help(a)rt.torproject.org"
+msgstr ""
+
+#: lib/gettor/i18n.py:46
+msgid ""
+"I will mail you a Tor package, if you tell me which one you want.\n"
+"Please select one of the following package names:\n"
+"\n"
+" windows\n"
+" macos-i386\n"
+" macos-ppc\n"
+" linux-i386\n"
+" linux-x86_64\n"
+" obfs-windows\n"
+" obfs-macos-i386\n"
+" obfs-macos-x86_64\n"
+" obfs-linux-i386\n"
+" obfs-linux-x86_64\n"
+" source"
+msgstr ""
+
+#: lib/gettor/i18n.py:61
+msgid ""
+"Please reply to this mail, and tell me a single package name anywhere \n"
+"in the body of your email."
+msgstr ""
+
+#: lib/gettor/i18n.py:64
+msgid ""
+"OBTAINING LOCALIZED VERSIONS OF TOR\n"
+"==================================="
+msgstr ""
+
+#: lib/gettor/i18n.py:67
+msgid ""
+"To get a version of Tor translated into your language, specify the\n"
+"language you want in the address you send the mail to:\n"
+"\n"
+" gettor+fa(a)torproject.org"
+msgstr ""
+
+#: lib/gettor/i18n.py:72
+msgid ""
+"This example will give you the requested package in a localized\n"
+"version for Farsi (Persian). Check below for a list of supported language\n"
+"codes. "
+msgstr ""
+
+#: lib/gettor/i18n.py:76
+msgid " List of supported locales:"
+msgstr ""
+
+#: lib/gettor/i18n.py:78
+msgid "Here is a list of all available languages:"
+msgstr "Tu je zoznam dostupných jazykov:"
+
+#: lib/gettor/i18n.py:80
+msgid ""
+" gettor+ar(a)torproject.org: Arabic\n"
+" gettor+de(a)torproject.org: German\n"
+" gettor+en(a)torproject.org: English\n"
+" gettor+es(a)torproject.org: Spanish\n"
+" gettor+fa(a)torproject.org: Farsi (Iran)\n"
+" gettor+fr(a)torproject.org: French\n"
+" gettor+it(a)torproject.org: Italian\n"
+" gettor+nl(a)torproject.org: Dutch\n"
+" gettor+pl(a)torproject.org: Polish\n"
+" gettor+ru(a)torproject.org: Russian\n"
+" gettor+zh(a)torproject.org: Chinese"
+msgstr ""
+
+#: lib/gettor/i18n.py:92
+msgid "If you select no language, you will receive the English version."
+msgstr "Ak si nevyberiete žiadny jazyk, bude zvolená anglická verzia."
+
+#: lib/gettor/i18n.py:94
+msgid ""
+"SMALLER SIZED PACKAGES\n"
+"======================"
+msgstr ""
+
+#: lib/gettor/i18n.py:97
+msgid ""
+"If your bandwith is low or your provider doesn't allow you to\n"
+"receive large attachments in your email, GetTor can send you several\n"
+"small packages instead of one big one."
+msgstr ""
+
+#: lib/gettor/i18n.py:101
+msgid ""
+"Simply include the keyword 'split' in a new line on its own (this part\n"
+"is important!) like so: \n"
+" \n"
+" windows\n"
+" split"
+msgstr ""
+
+#: lib/gettor/i18n.py:107
+msgid ""
+"Sending this text in an email to GetTor will cause it to send you \n"
+"the Tor Browser Bundle in a number of 1,4MB attachments."
+msgstr ""
+
+#: lib/gettor/i18n.py:110
+msgid ""
+"After having received all parts, you need to re-assemble them to \n"
+"one package again. This is done as follows:"
+msgstr ""
+
+#: lib/gettor/i18n.py:113
+msgid "1.) Save all received attachments into one folder on your disk."
+msgstr "1.) Uložte všetky prevzaté prílohy do jedného priečinka na disku."
+
+#: lib/gettor/i18n.py:115
+msgid ""
+"2.) Unzip all files ending in \".z\". If you saved all attachments to\n"
+"a fresh folder before, simply unzip all files in that folder. If you don't\n"
+"know how to unzip the .z files, please see the UNPACKING THE FILES section."
+msgstr "2.) Rozbaľte všetky súbory končiace sa na \".z\". Ak ste uložili všetky prílohy\ndo nového priečinka už predtým, stačí len rozbaliť všetky súbory\nv tomto priečinku. Ak neviete, ako rozbaliť .z súbory, prezrite si, prosím,\nodsek ROZBAĽOVANIE SÚBOROV."
+
+#: lib/gettor/i18n.py:119
+msgid ""
+"3.) Verify all files as described in the mail you received with \n"
+"each package. (gpg --verify)"
+msgstr "3.) Overte všetky súbory podľa inštrukcií v e-maile, ktorý ste\nobdržali s každým balíčkom. (gpg --verify)"
+
+#: lib/gettor/i18n.py:122
+msgid ""
+"4.) Now unpack the multi-volume archive into one file by double-\n"
+"clicking the file ending in \"..split.part01.exe\". This should start the \n"
+"process automatically."
+msgstr "4.) Teraz rozbaľte archív pozostávajúci z viacerých častí dvojitým\nkliknutím na súbor končiaci sa na \"..split.part01.exe\". To by malo \nautomaticky spustiť celý proces rozbaľovania."
+
+#: lib/gettor/i18n.py:126
+msgid ""
+"5.) After unpacking is finished, you should find a newly created \n"
+"\".exe\" file in your destination folder. Simply doubleclick\n"
+"that and Tor Browser Bundle should start within a few seconds."
+msgstr ""
+
+#: lib/gettor/i18n.py:130
+msgid "6.) That's it. You're done. Thanks for using Tor and have fun!"
+msgstr ""
+
+#: lib/gettor/i18n.py:132
+msgid ""
+"SUPPORT\n"
+"======="
+msgstr ""
+
+#: lib/gettor/i18n.py:138
+msgid ""
+"Here's your requested software as a zip file. Please unzip the\n"
+"package and verify the signature."
+msgstr ""
+
+#: lib/gettor/i18n.py:141
+msgid ""
+"VERIFY SIGNATURE\n"
+"================\n"
+"If your computer has GnuPG installed, use the gpg commandline \n"
+"tool as follows after unpacking the zip file:\n"
+"\n"
+" gpg --verify tor-browser-1.3.24_en-US.exe.asc tor-browser-1.3.24_en-US.exe"
+msgstr ""
+
+#: lib/gettor/i18n.py:148
+msgid ""
+"The output should look somewhat like this:\n"
+"\n"
+" gpg: Good signature from 'Erinn Clark <...>'"
+msgstr ""
+
+#: lib/gettor/i18n.py:152
+msgid ""
+"If you're not familiar with commandline tools, try looking for\n"
+"a graphical user interface for GnuPG on this website:\n"
+"\n"
+" http://www.gnupg.org/related_software/frontends.html"
+msgstr ""
+
+#: lib/gettor/i18n.py:157
+msgid ""
+"BLOCKED ACCESS / CENSORSHIP\n"
+"==========================="
+msgstr ""
+
+#: lib/gettor/i18n.py:160
+msgid ""
+"If your Internet connection blocks access to the Tor network, you\n"
+"may need a bridge relay. Bridge relays (or \"bridges\" for short)\n"
+"are Tor relays that aren't listed in the main directory. Since there\n"
+"is no complete public list of them, even if your ISP is filtering\n"
+"connections to all the known Tor relays, they probably won't be able\n"
+"to block all the bridges."
+msgstr ""
+
+#: lib/gettor/i18n.py:167
+msgid ""
+"You can acquire a bridge by sending an email that contains \"get bridges\"\n"
+"in the body of the email to the following email address:\n"
+"\n"
+" bridges(a)torproject.org"
+msgstr ""
+
+#: lib/gettor/i18n.py:172
+msgid ""
+"It is also possible to fetch bridges with a web browser at the following\n"
+"url: https://bridges.torproject.org/"
+msgstr ""
+
+#: lib/gettor/i18n.py:175
+msgid ""
+"Another censorship circumvention tool you can request from GetTor is\n"
+"the Tor Obfsproxy Browser Bundle. Please read the package descriptions for\n"
+"which package you should request to receive this."
+msgstr ""
+
+#: lib/gettor/i18n.py:179
+msgid ""
+"IMPORTANT NOTE:\n"
+"Since this is part of a split-file request, you need to wait for\n"
+"all split files to be received by you before you can save them all\n"
+"into the same directory and unpack them by double-clicking the\n"
+"first file."
+msgstr ""
+
+#: lib/gettor/i18n.py:185
+msgid ""
+"Packages might arrive out of order! Please make sure you received\n"
+"all packages before you attempt to unpack them!"
+msgstr ""
+
+#: lib/gettor/i18n.py:188
+#, python-format
+msgid ""
+"It was successfully understood. Your request is currently being processed.\n"
+"Your package (%s) should arrive within the next ten minutes."
+msgstr ""
+
+#: lib/gettor/i18n.py:191
+msgid ""
+"If it doesn't arrive, the package might be too big for your mail provider.\n"
+"Try resending the mail from a GMAIL.COM, YAHOO.CN or YAHOO.COM account."
+msgstr ""
+
+#: lib/gettor/i18n.py:194
+msgid ""
+"Unfortunately we are currently experiencing problems and we can't fulfill\n"
+"your request right now. Please be patient as we try to resolve this issue."
+msgstr ""
+
+#: lib/gettor/i18n.py:197
+msgid ""
+"Unfortunately there is no split package available for the package you\n"
+"requested. Please send us another package name or request the same package \n"
+"again, but remove the 'split' keyword. In that case we'll send you the whole \n"
+"package. Make sure this is what you want."
+msgstr ""
+
+#: lib/gettor/i18n.py:202
+msgid ""
+"UNPACKING THE FILES\n"
+"==================="
+msgstr "ROZBAĽOVANIE SÚBOROV\n==================="
+
+#: lib/gettor/i18n.py:205
+msgid ""
+"The easiest way to unpack the files you received is to install 7-Zip,\n"
+"a free file compression/uncompression tool. If it isn't installed on\n"
+"your computer yet, you can download it here:\n"
+"\n"
+" http://www.7-zip.org/"
+msgstr ""
+
+#: lib/gettor/i18n.py:211
+msgid ""
+"When 7-Zip is installed, you can open the .z archive you received from\n"
+"us by double-clicking on it."
+msgstr ""
+
+#: lib/gettor/i18n.py:214
+msgid ""
+"An alternative way to get the .z files extraced is to rename them to\n"
+".zip. For example, if you recevied a file called \"windows.z\", rename it to \n"
+"\"windows.zip\". You should then be able to extract the archive with common \n"
+"file archiver programs that probably are already installed on your computer."
+msgstr ""
+
+#: lib/gettor/i18n.py:219
+msgid ""
+"Please reply to this mail, and tell me a single package name anywhere\n"
+"in your reply. Here's a short explanation of what these packages are:"
+msgstr ""
+
+#: lib/gettor/i18n.py:222
+msgid ""
+"windows:\n"
+"The Tor Browser Bundle package for Windows operating systems. If you're \n"
+"running some version of Windows, like Windows XP, Windows Vista or \n"
+"Windows 7, this is the package you should get."
+msgstr ""
+
+#: lib/gettor/i18n.py:227
+msgid ""
+"macos-i386:\n"
+"The Tor Browser Bundle package for OS X, Intel CPU architecture. In \n"
+"general, newer Mac hardware will require you to use this package."
+msgstr ""
+
+#: lib/gettor/i18n.py:231
+msgid ""
+"macos-ppc:\n"
+"This is an older installer (the \"Vidalia bundle\") for older Macs running\n"
+"OS X on PowerPC CPUs. Note that this package will be deprecated soon."
+msgstr ""
+
+#: lib/gettor/i18n.py:235
+msgid ""
+"linux-i386:\n"
+"The Tor Browser Bundle package for Linux, 32bit versions."
+msgstr ""
+
+#: lib/gettor/i18n.py:238
+msgid ""
+"Note that this package is rather large and needs your email provider to \n"
+"allow for attachments of about 30MB in size."
+msgstr ""
+
+#: lib/gettor/i18n.py:241
+msgid ""
+"linux-x86_64:\n"
+"The Tor Browser Bundle package for Linux, 64bit versions."
+msgstr ""
+
+#: lib/gettor/i18n.py:244
+msgid ""
+"obfs-windows:\n"
+"The Tor Obfsproxy Browser Bundle for Windows operating systems. If you need\n"
+"strong censorship circumvention and you are running some version of the \n"
+"Windows, like Windows XP, Windows Vista or Windows 7, this is the package\n"
+"you should get."
+msgstr ""
+
+#: lib/gettor/i18n.py:250
+msgid ""
+"obfs-macos-i386:\n"
+"The Tor Obfsproxy Browser Bundle package for OS X, 32bit Intel CPU \n"
+"architecture."
+msgstr ""
+
+#: lib/gettor/i18n.py:254
+msgid ""
+"obfs-macos-x86_64:\n"
+"The Tor Obfsproxy Browser Bundle package for OS X, 64bit Intel CPU \n"
+"architecture."
+msgstr ""
+
+#: lib/gettor/i18n.py:258
+msgid ""
+"obfs-linux-i386:\n"
+"The Tor Obfsproxy Browser Bundle package for Linux, 32bit Intel CPU \n"
+"architecture."
+msgstr ""
+
+#: lib/gettor/i18n.py:262
+msgid ""
+"obfs-linux-x86_64:\n"
+"The Tor Obfsproxy Browser Bundle package for Linux, 64bit Intel CPU \n"
+"architecture."
+msgstr ""
+
+#: lib/gettor/i18n.py:266
+msgid ""
+"source:\n"
+"The Tor source code, for experts. Most users do not want this package."
+msgstr ""
+
+#: lib/gettor/i18n.py:269
+msgid ""
+"FREQUENTLY ASKED QUESTIONS\n"
+"=========================="
+msgstr ""
+
+#: lib/gettor/i18n.py:272
+msgid "What is Tor?"
+msgstr ""
+
+#: lib/gettor/i18n.py:274
+msgid "The name \"Tor\" can refer to several different components."
+msgstr ""
+
+#: lib/gettor/i18n.py:276
+msgid ""
+"The Tor software is a program you can run on your computer that helps \n"
+"keep you safe on the Internet. Tor protects you by bouncing your \n"
+"communications around a distributed network of relays run by volunteers \n"
+"all around the world: it prevents somebody watching your Internet connection \n"
+"from learning what sites you visit, and it prevents the sites you visit from \n"
+"learning your physical location. This set of volunteer relays is called the \n"
+"Tor network. You can read more about how Tor works here:\n"
+"\n"
+" https://www.torproject.org/about/overview.html.en"
+msgstr ""
+
+#: lib/gettor/i18n.py:286
+msgid "What is the Tor Browser Bundle?"
+msgstr ""
+
+#: lib/gettor/i18n.py:288
+msgid ""
+"The Browser Bundle (TBB) is the package we recommend to most users. \n"
+"The bundle comes with everything you need to safely browse the Internet.\n"
+"Just extract it and run."
+msgstr ""
+
+#: lib/gettor/i18n.py:292
+msgid "What package should I request?"
+msgstr ""
+
+#: lib/gettor/i18n.py:294
+msgid ""
+"This depends on the operating system you use. For instance, if your\n"
+"operating system is Microsoft Windows, you should request \"windows\". Here\n"
+"is a short explanation of all packages to request and what operating \n"
+"systems there are suitable for:"
+msgstr ""
+
+#: lib/gettor/i18n.py:299
+msgid "How do I extract the file(s) you sent me?"
+msgstr ""
+
+#: lib/gettor/i18n.py:301
+msgid "QUESTION:"
+msgstr ""
+
+#: lib/gettor/i18n.py:303
+msgid "ANSWER:"
+msgstr ""
+
+#: lib/gettor/i18n.py:305
+#, python-format
+msgid ""
+"Sorry, but the package you requested (%s) is too large for your \n"
+"provider to accept as an attachment. Try using another provider that allows \n"
+"for larger email attachments. Or try one of the following mirrors:\n"
+"\n"
+" https://www.oignon.net/dist/torbrowser/\n"
+" https://tor.beme-it.de/dist/torbrowser/\n"
+" https://www.torservers.net/mirrors/torproject.org/dist/torbrowser/"
+msgstr ""
1
0
22 Jul '14
commit a959bd0cd09b12ee9150cd1ddc72334ad96029af
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Jul 22 14:45:03 2014 +0000
Update translations for bridgedb
---
sk_SK/LC_MESSAGES/bridgedb.po | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sk_SK/LC_MESSAGES/bridgedb.po b/sk_SK/LC_MESSAGES/bridgedb.po
index aa625e9..2ea3575 100644
--- a/sk_SK/LC_MESSAGES/bridgedb.po
+++ b/sk_SK/LC_MESSAGES/bridgedb.po
@@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: The Tor Project\n"
"Report-Msgid-Bugs-To: 'https://trac.torproject.org/projects/tor/newticket?component=BridgeDB&keywo…'\n"
"POT-Creation-Date: 2014-06-06 21:46+0000\n"
-"PO-Revision-Date: 2014-07-22 14:11+0000\n"
+"PO-Revision-Date: 2014-07-22 14:31+0000\n"
"Last-Translator: once <matejbacik(a)gmail.com>\n"
"Language-Team: Slovak (Slovakia) (http://www.transifex.com/projects/p/torproject/language/sk_SK/)\n"
"MIME-Version: 1.0\n"
@@ -187,7 +187,7 @@ msgstr ""
#: lib/bridgedb/strings.py:114
msgid "Your browser is not displaying images properly."
-msgstr ""
+msgstr "Váš prehliadač nezobrazuje obrázky správne."
#: lib/bridgedb/strings.py:115
msgid "Enter the characters from the image above..."
1
0
[translation/torbutton-torbuttondtd] Update translations for torbutton-torbuttondtd
by translation@torproject.org 22 Jul '14
by translation@torproject.org 22 Jul '14
22 Jul '14
commit 4930ef3d2c08d2c3de3a9b3d9f9c13454dade290
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Jul 22 14:15:56 2014 +0000
Update translations for torbutton-torbuttondtd
---
sk_SK/torbutton.dtd | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sk_SK/torbutton.dtd b/sk_SK/torbutton.dtd
index bbf33d4..0e35887 100644
--- a/sk_SK/torbutton.dtd
+++ b/sk_SK/torbutton.dtd
@@ -101,7 +101,7 @@
<!ENTITY torbutton.prefs.startup "Startup">
<!ENTITY torbutton.prefs.block_tor_file_net "Block Tor access to network from file:// urls (recommended)">
<!ENTITY torbutton.prefs.block_nontor_file_net "Block Non-Tor access to network from file:// urls">
-<!ENTITY torbutton.prefs.restore_defaults "Restore Defaults">
+<!ENTITY torbutton.prefs.restore_defaults "Obnoviť pôvodné nastavenia">
<!ENTITY torbutton.prefs.test_settings "Skontrolovať nastavenia">
<!ENTITY torbutton.prefs.test_auto "Test my Tor settings after the first time I toggle on every Firefox start">
<!ENTITY torbutton.prefs.disable_livemarks "Disable livemarks updates during Tor usage">
1
0
22 Jul '14
commit a3ea0028d03e16ca258ace5be3867af96965fa02
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Jul 22 14:15:33 2014 +0000
Update translations for torbirdy
---
sk_SK/torbirdy.dtd | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sk_SK/torbirdy.dtd b/sk_SK/torbirdy.dtd
index d3988da..a4331d4 100644
--- a/sk_SK/torbirdy.dtd
+++ b/sk_SK/torbirdy.dtd
@@ -12,9 +12,9 @@
<!ENTITY torbirdy.prefs.save.button "Uložiť">
<!ENTITY torbirdy.prefs.save.key "s">
<!ENTITY torbirdy.prefs.cancel.button "Zrušiť">
-<!ENTITY torbirdy.prefs.extra2.button "Restore Defaults">
+<!ENTITY torbirdy.prefs.extra2.button "Obnoviť pôvodné nastavenia">
<!ENTITY torbirdy.prefs.extra2.key "d">
-<!ENTITY torbirdy.prefs.testproxy.button "Test Proxy Settings">
+<!ENTITY torbirdy.prefs.testproxy.button "Testovať Proxy nastavenia">
<!ENTITY torbirdy.prefs.testproxy.key "p">
<!ENTITY torbirdy.prefs.proxy.label "Proxy">
<!ENTITY torbirdy.prefs.privacy.label "Privacy">
1
0
22 Jul '14
commit 40ff5fe4c28a280d93b26ab442de0058f4d9345b
Author: Translation commit bot <translation(a)torproject.org>
Date: Tue Jul 22 14:15:02 2014 +0000
Update translations for bridgedb
---
sk_SK/LC_MESSAGES/bridgedb.po | 147 ++++++++++++++++++++++++-----------------
1 file changed, 86 insertions(+), 61 deletions(-)
diff --git a/sk_SK/LC_MESSAGES/bridgedb.po b/sk_SK/LC_MESSAGES/bridgedb.po
index f765173..aa625e9 100644
--- a/sk_SK/LC_MESSAGES/bridgedb.po
+++ b/sk_SK/LC_MESSAGES/bridgedb.po
@@ -3,13 +3,14 @@
# This file is distributed under the same license as the BridgeDB project.
#
# Translators:
+# once <matejbacik(a)gmail.com>, 2014
msgid ""
msgstr ""
"Project-Id-Version: The Tor Project\n"
"Report-Msgid-Bugs-To: 'https://trac.torproject.org/projects/tor/newticket?component=BridgeDB&keywo…'\n"
-"POT-Creation-Date: 2014-05-16 18:39+0000\n"
-"PO-Revision-Date: 2011-02-19 16:53+0000\n"
-"Last-Translator: Isis Lovecruft <isis(a)torproject.org>\n"
+"POT-Creation-Date: 2014-06-06 21:46+0000\n"
+"PO-Revision-Date: 2014-07-22 14:11+0000\n"
+"Last-Translator: once <matejbacik(a)gmail.com>\n"
"Language-Team: Slovak (Slovakia) (http://www.transifex.com/projects/p/torproject/language/sk_SK/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
@@ -20,25 +21,22 @@ msgstr ""
#. TRANSLATORS: Please DO NOT translate the following words and/or phrases in
#. any string (regardless of capitalization and/or punctuation):
-#. "bridge"
-#. "bridges"
#. "BridgeDB"
#. "pluggable transport"
#. "pluggable transports"
#. "obfs2"
#. "obfs3"
#. "scramblesuit"
-#. "fte"
+#. "fteproxy"
#. "Tor"
#. "Tor Browser"
-#. "TBB"
-#: lib/bridgedb/HTTPServer.py:124
+#: lib/bridgedb/HTTPServer.py:121
msgid "Sorry! Something went wrong with your request."
-msgstr ""
+msgstr "Prepáčte! Pri spracovaní vašej požiadavky sa vyskytla chyba."
#: lib/bridgedb/strings.py:18
msgid "[This is an automated message; please do not reply.]"
-msgstr ""
+msgstr "[Toto je automatická správa; prosím, neodpovedajte.]"
#: lib/bridgedb/strings.py:20
msgid "Here are your bridges:"
@@ -56,39 +54,44 @@ msgid ""
"COMMANDs: (combine COMMANDs to specify multiple options simultaneously)"
msgstr ""
-#: lib/bridgedb/strings.py:27
+#. TRANSLATORS: Please DO NOT translate the word "BridgeDB".
+#: lib/bridgedb/strings.py:28
msgid "Welcome to BridgeDB!"
-msgstr ""
+msgstr "Vitajte v BridgeDB!"
#. TRANSLATORS: Please DO NOT translate the words "transport" or "TYPE".
-#: lib/bridgedb/strings.py:29
+#: lib/bridgedb/strings.py:30
msgid "Currently supported transport TYPEs:"
msgstr ""
-#: lib/bridgedb/strings.py:30
+#: lib/bridgedb/strings.py:31
#, python-format
msgid "Hey, %s!"
msgstr ""
-#: lib/bridgedb/strings.py:31
+#: lib/bridgedb/strings.py:32
msgid "Hello, friend!"
msgstr ""
-#: lib/bridgedb/strings.py:32 lib/bridgedb/templates/base.html:100
+#: lib/bridgedb/strings.py:33 lib/bridgedb/templates/base.html:100
msgid "Public Keys"
-msgstr ""
+msgstr "Verejné kľúče"
#. TRANSLATORS: This string will end up saying something like:
#. "This email was generated with rainbows, unicorns, and sparkles
#. for alice(a)example.com on Friday, 09 May, 2014 at 18:59:39."
-#: lib/bridgedb/strings.py:36
+#: lib/bridgedb/strings.py:37
#, python-format
msgid ""
"This email was generated with rainbows, unicorns, and sparkles\n"
"for %s on %s at %s."
msgstr ""
-#: lib/bridgedb/strings.py:42
+#. TRANSLATORS: Please DO NOT translate "BridgeDB".
+#. TRANSLATORS: Please DO NOT translate "Pluggable Transports".
+#. TRANSLATORS: Please DO NOT translate "Tor".
+#. TRANSLATORS: Please DO NOT translate "Tor Network".
+#: lib/bridgedb/strings.py:47
#, python-format
msgid ""
"BridgeDB can provide bridges with several %stypes of Pluggable Transports%s,\n"
@@ -98,14 +101,20 @@ msgid ""
"\n"
msgstr ""
-#: lib/bridgedb/strings.py:48
+#. TRANSLATORS: Please DO NOT translate "Pluggable Transports".
+#: lib/bridgedb/strings.py:54
msgid ""
"Some bridges with IPv6 addresses are also available, though some Pluggable\n"
"Transports aren't IPv6 compatible.\n"
"\n"
msgstr ""
-#: lib/bridgedb/strings.py:52
+#. TRANSLATORS: Please DO NOT translate "BridgeDB".
+#. TRANSLATORS: The phrase "plain-ol'-vanilla" means "plain, boring,
+#. regular, or unexciting". Like vanilla ice cream. It refers to bridges
+#. which do not have Pluggable Transports, and only speak the regular,
+#. boring Tor protocol. Translate it as you see fit. Have fun with it.
+#: lib/bridgedb/strings.py:63
#, python-format
msgid ""
"Additionally, BridgeDB has plenty of plain-ol'-vanilla bridges %s without any\n"
@@ -114,20 +123,20 @@ msgid ""
"\n"
msgstr ""
-#: lib/bridgedb/strings.py:65
+#: lib/bridgedb/strings.py:76
msgid "What are bridges?"
msgstr ""
-#: lib/bridgedb/strings.py:66
+#: lib/bridgedb/strings.py:77
#, python-format
msgid "%s Bridges %s are Tor relays that help you circumvent censorship."
msgstr ""
-#: lib/bridgedb/strings.py:71
+#: lib/bridgedb/strings.py:82
msgid "I need an alternative way of getting bridges!"
msgstr ""
-#: lib/bridgedb/strings.py:72
+#: lib/bridgedb/strings.py:83
#, python-format
msgid ""
"Another way to get bridges is to send an email to %s. Please note that you must\n"
@@ -135,75 +144,83 @@ msgid ""
"%s or %s."
msgstr ""
-#: lib/bridgedb/strings.py:79
+#: lib/bridgedb/strings.py:90
msgid "My bridges don't work! I need help!"
msgstr ""
-#: lib/bridgedb/strings.py:80
+#. TRANSLATORS: Please DO NOT translate "Tor".
+#: lib/bridgedb/strings.py:92
#, python-format
msgid "If your Tor doesn't work, you should email %s."
msgstr ""
-#: lib/bridgedb/strings.py:81
+#. TRANSLATORS: Please DO NOT translate "Pluggable Transports".
+#. TRANSLATORS: Please DO NOT translate "Tor Browser".
+#. TRANSLATORS: Please DO NOT translate "Tor".
+#: lib/bridgedb/strings.py:96
msgid ""
"Try including as much info about your case as you can, including the list of\n"
"bridges and Pluggable Transports you tried to use, your Tor Browser version,\n"
"and any messages which Tor gave out, etc."
msgstr ""
-#: lib/bridgedb/strings.py:88
+#: lib/bridgedb/strings.py:103
msgid "Here are your bridge lines:"
msgstr ""
-#: lib/bridgedb/strings.py:89
+#: lib/bridgedb/strings.py:104
msgid "Get Bridges!"
msgstr ""
-#: lib/bridgedb/strings.py:93
+#: lib/bridgedb/strings.py:108
msgid "Please select options for bridge type:"
msgstr ""
-#: lib/bridgedb/strings.py:94
+#: lib/bridgedb/strings.py:109
msgid "Do you need IPv6 addresses?"
msgstr ""
-#: lib/bridgedb/strings.py:95
+#: lib/bridgedb/strings.py:110
#, python-format
msgid "Do you need a %s?"
msgstr ""
-#: lib/bridgedb/strings.py:99
+#: lib/bridgedb/strings.py:114
msgid "Your browser is not displaying images properly."
msgstr ""
-#: lib/bridgedb/strings.py:100
+#: lib/bridgedb/strings.py:115
msgid "Enter the characters from the image above..."
-msgstr ""
+msgstr "Zadajte znaky z obrázka vyššie..."
-#: lib/bridgedb/strings.py:104
+#: lib/bridgedb/strings.py:119
msgid "How to start using your bridges"
msgstr ""
-#: lib/bridgedb/strings.py:105
+#. TRANSLATORS: Please DO NOT translate "Tor Browser".
+#: lib/bridgedb/strings.py:121
#, python-format
msgid ""
"To enter bridges into Tor Browser, follow the instructions on the %s Tor\n"
"Browser download page %s to start Tor Browser."
msgstr ""
-#: lib/bridgedb/strings.py:108
+#. TRANSLATORS: Please DO NOT translate "Tor".
+#: lib/bridgedb/strings.py:125
msgid ""
"When the 'Tor Network Settings' dialogue pops up, click 'Configure' and follow\n"
"the wizard until it asks:"
msgstr ""
-#: lib/bridgedb/strings.py:111
+#. TRANSLATORS: Please DO NOT translate "Tor".
+#: lib/bridgedb/strings.py:129
msgid ""
"Does your Internet Service Provider (ISP) block or otherwise censor connections\n"
"to the Tor network?"
msgstr ""
-#: lib/bridgedb/strings.py:114
+#. TRANSLATORS: Please DO NOT translate "Tor".
+#: lib/bridgedb/strings.py:133
msgid ""
"Select 'Yes' and then click 'Next'. To configure your new bridges, copy and\n"
"paste the bridge lines into the text input box. Finally, click 'Connect', and\n"
@@ -211,24 +228,29 @@ msgid ""
"button in the 'Tor Network Settings' wizard for further assistance."
msgstr ""
-#: lib/bridgedb/strings.py:122
+#: lib/bridgedb/strings.py:141
msgid "Displays this message."
msgstr ""
-#: lib/bridgedb/strings.py:123
+#. TRANSLATORS: Please try to make it clear that "vanilla" here refers to the
+#. same non-Pluggable Transport bridges described above as being
+#. "plain-ol'-vanilla" bridges.
+#: lib/bridgedb/strings.py:145
msgid "Request vanilla bridges."
msgstr ""
-#: lib/bridgedb/strings.py:124
+#: lib/bridgedb/strings.py:146
msgid "Request IPv6 bridges."
msgstr ""
#. TRANSLATORS: Please DO NOT translate the word the word "TYPE".
-#: lib/bridgedb/strings.py:126
+#: lib/bridgedb/strings.py:148
msgid "Request a Pluggable Transport by TYPE."
msgstr ""
-#: lib/bridgedb/strings.py:127
+#. TRANSLATORS: Please DO NOT translate "BridgeDB".
+#. TRANSLATORS: Please DO NOT translate "GnuPG".
+#: lib/bridgedb/strings.py:151
msgid "Get a copy of BridgeDB's public GnuPG key."
msgstr ""
@@ -248,15 +270,19 @@ msgstr ""
msgid "Contact"
msgstr ""
-#: lib/bridgedb/templates/bridges.html:65
+#. TRANSLATORS: Please translate this into some silly way to say
+#. "There was a problem!" in your language. For example,
+#. for Italian, you might translate this into "Mama mia!",
+#. or for French: "Sacrebleu!". :)
+#: lib/bridgedb/templates/bridges.html:66
msgid "Uh oh, spaghettios!"
msgstr ""
-#: lib/bridgedb/templates/bridges.html:70
+#: lib/bridgedb/templates/bridges.html:72
msgid "There currently aren't any bridges available..."
msgstr ""
-#: lib/bridgedb/templates/bridges.html:71
+#: lib/bridgedb/templates/bridges.html:73
#, python-format
msgid ""
" Perhaps you should try %s going back %s and choosing a different bridge "
@@ -266,7 +292,7 @@ msgstr ""
#: lib/bridgedb/templates/index.html:11
#, python-format
msgid "Step %s1%s"
-msgstr ""
+msgstr "Krok %s1%s"
#: lib/bridgedb/templates/index.html:13
#, python-format
@@ -276,7 +302,7 @@ msgstr ""
#: lib/bridgedb/templates/index.html:25
#, python-format
msgid "Step %s2%s"
-msgstr ""
+msgstr "Krok %s2%s"
#: lib/bridgedb/templates/index.html:27
#, python-format
@@ -286,7 +312,7 @@ msgstr ""
#: lib/bridgedb/templates/index.html:36
#, python-format
msgid "Step %s3%s"
-msgstr ""
+msgstr "Krok %s3%s"
#: lib/bridgedb/templates/index.html:38
#, python-format
@@ -297,36 +323,35 @@ msgstr ""
#. beginning of words are present in your final translation. Thanks!
#. (These are used to insert HTML5 underlining tags, to mark accesskeys
#. for disabled users.)
-#. TRANSLATORS: Please do NOT translate the word "bridges"!
-#: lib/bridgedb/templates/options.html:39
+#: lib/bridgedb/templates/options.html:38
#, python-format
msgid "%sJ%sust give me bridges!"
msgstr ""
-#: lib/bridgedb/templates/options.html:53
+#: lib/bridgedb/templates/options.html:52
msgid "Advanced Options"
-msgstr ""
+msgstr "Rozšírené nastavenia"
-#: lib/bridgedb/templates/options.html:89
+#: lib/bridgedb/templates/options.html:88
msgid "No"
msgstr "Nie"
-#: lib/bridgedb/templates/options.html:90
+#: lib/bridgedb/templates/options.html:89
msgid "none"
msgstr ""
#. TRANSLATORS: Please make sure the '%s' surrounding single letters at the
#. beginning of words are present in your final translation. Thanks!
#. TRANSLATORS: Translate "Yes!" as in "Yes! I do need IPv6 addresses."
-#: lib/bridgedb/templates/options.html:131
+#: lib/bridgedb/templates/options.html:130
#, python-format
msgid "%sY%ses!"
-msgstr ""
+msgstr "%sÁ%sno!"
#. TRANSLATORS: Please make sure the '%s' surrounding single letters at the
#. beginning of words are present in your final translation. Thanks!
#. TRANSLATORS: Please do NOT translate the word "bridge"!
-#: lib/bridgedb/templates/options.html:155
+#: lib/bridgedb/templates/options.html:154
#, python-format
msgid "%sG%set Bridges"
msgstr ""
1
0
Author: phobos
Date: 2014-07-22 13:46:17 +0000 (Tue, 22 Jul 2014)
New Revision: 26883
Modified:
website/trunk/include/tor-mirrors.csv
Log:
add new mirror
Modified: website/trunk/include/tor-mirrors.csv
===================================================================
--- website/trunk/include/tor-mirrors.csv 2014-07-22 09:26:34 UTC (rev 26882)
+++ website/trunk/include/tor-mirrors.csv 2014-07-22 13:46:17 UTC (rev 26883)
@@ -104,3 +104,4 @@
webmaster[at]hackabit.nl, Hackabit.nl, NL, The Netherlands, Europe, TRUE, FALSE, No, http://hackabit.nl/tor/, https://hackabit.nl/tor/, , , http://hackabit.nl/tor/dist/, https://hackabit.nl/tor/dist/, , ,
noc AT bbln DOT org, BBLN, NL, The Netherlands, Europe, TRUE, TRUE, No, http://mirror2.bbln.org/torproject/, https://mirror2.bbln.org/torproject/, rsync://mirror2.bbln.org/torproject/, ftp://mirror2.bbln.org/torproject/, http://mirror2.bbln.org/torproject/dist/, https://mirror2.bbln.org/torproject/dist/, rsync://mirror2.bbln.org/torproject/dist/, , Sat Jul 19 23:55:06 2014
noc AT bbln DOT org, BBLN, FR, France, Europe, TRUE, TRUE, No, http://mirror.bbln.org/torproject/, https://mirror.bbln.org/torproject/, rsync://mirror.bbln.org/torproject/, ftp://mirror.bbln.org/torproject/, http://mirror.bbln.org/torproject/dist/, https://mirror.bbln.org/torproject/dist/, rsync://mirror.bbln.org/torproject/dist/, , Sat Jul 19 23:55:06 2014
+torsupport AT tb-itf DOT de, TB-ITF, , DE, Germany, Europe, TRUE, TRUE, No, http://tormirror.tb-itf-tor.de, https://tormirror.tb-itf-tor.de, , , , http://tormirror.tb-itf-tor.de/dist/, https://tormirror.tb-itf-tor.de/dist/, , ,
1
0
22 Jul '14
commit 3a2c416b036e1a4bb7af06572d57bb225acc0996
Author: George Kadianakis <desnacked(a)riseup.net>
Date: Wed Jul 16 18:30:41 2014 +0300
Do the release ritual for obfsproxy-0.2.11.
---
ChangeLog | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ChangeLog b/ChangeLog
index bca3df6..c97ea11 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,4 @@
-Changes in version 0.2.11 - UNRELEASED:
+Changes in version 0.2.11 - 2014-07-16:
- Write a 'server_password' file with the scramblesuit password to
make it easier for bridge operators to find their password. Patch
by Philipp Winter. Fixes #10887.
1
0
[obfsproxy/master] Add txsocksx and parsley as py2exe dependencies.
by asn@torproject.org 22 Jul '14
by asn@torproject.org 22 Jul '14
22 Jul '14
commit 4d8bcb4b3671fd64d52040fa1cdfa35e48c17021
Author: George Kadianakis <desnacked(a)riseup.net>
Date: Tue Jul 22 13:48:02 2014 +0300
Add txsocksx and parsley as py2exe dependencies.
---
setup_py2exe.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/setup_py2exe.py b/setup_py2exe.py
index 76a2360..ea1a7ab 100644
--- a/setup_py2exe.py
+++ b/setup_py2exe.py
@@ -14,7 +14,7 @@ setup(
options={
"build": {"build_base": build_path},
"py2exe": {
- "includes": ["twisted", "pyptlib", "Crypto"],
+ "includes": ["twisted", "pyptlib", "Crypto", "parsley", "txsocksx"],
"dist_dir": dist_path,
}
}
1
0