diff --git a/source/net/yacy/document/LibraryProvider.java b/source/net/yacy/document/LibraryProvider.java index 6044457b5..de27f3f0f 100644 --- a/source/net/yacy/document/LibraryProvider.java +++ b/source/net/yacy/document/LibraryProvider.java @@ -45,7 +45,8 @@ import net.yacy.document.geolocalization.OverarchingLocalization; import net.yacy.kelondro.logging.Log; import net.yacy.kelondro.util.FileUtils; -public class LibraryProvider { +public class LibraryProvider +{ private static final String path_to_source_dictionaries = "source"; private static final String path_to_did_you_mean_dictionaries = "didyoumean"; @@ -58,16 +59,19 @@ public class LibraryProvider { private static File dictRoot = null; public static enum Dictionary { - GEODB0("geo0", "http://downloads.sourceforge.net/project/opengeodb/Data/0.2.5a/opengeodb-0.2.5a-UTF8-sql.gz"), - GEODB1("geo1", "http://fa-technik.adfc.de/code/opengeodb/dump/opengeodb-02621_2010-03-16.sql.gz"), - GEON0("geon0", "http://download.geonames.org/export/dump/cities1000.zip"), - DRW0("drw0", "http://www.ids-mannheim.de/kl/derewo/derewo-v-100000t-2009-04-30-0.1.zip"); + GEODB0( + "geo0", + "http://downloads.sourceforge.net/project/opengeodb/Data/0.2.5a/opengeodb-0.2.5a-UTF8-sql.gz" ), + GEODB1( "geo1", "http://fa-technik.adfc.de/code/opengeodb/dump/opengeodb-02624_2011-10-17.sql.gz" ), + GEON0( "geon0", "http://download.geonames.org/export/dump/cities1000.zip" ), + DRW0( "drw0", "http://www.ids-mannheim.de/kl/derewo/derewo-v-100000t-2009-04-30-0.1.zip" ); public String nickname, url, filename; + private Dictionary(final String nickname, final String url) { try { this.filename = new MultiProtocolURI(url).getFileName(); - } catch (final MalformedURLException e) { + } catch ( final MalformedURLException e ) { assert false; } this.nickname = nickname; @@ -77,41 +81,45 @@ public class LibraryProvider { public File file() { return new File(dictSource, this.filename); } + public File fileDisabled() { return new File(dictSource, this.filename + disabledExtension); } } /** - * initialize the LibraryProvider as static class. - * This assigns default paths, and initializes the dictionary classes - * Additionally, if default dictionaries are given in the source path, - * they are translated into the input format inside the DATA/DICTIONARIES directory - * + * initialize the LibraryProvider as static class. This assigns default paths, and initializes the + * dictionary classes Additionally, if default dictionaries are given in the source path, they are + * translated into the input format inside the DATA/DICTIONARIES directory + * * @param pathToSource * @param pathToDICTIONARIES */ public static void initialize(final File rootPath) { - dictSource = new File(rootPath, path_to_source_dictionaries); - if (!dictSource.exists()) dictSource.mkdirs(); - dictRoot = rootPath; + dictSource = new File(rootPath, path_to_source_dictionaries); + if ( !dictSource.exists() ) { + dictSource.mkdirs(); + } + dictRoot = rootPath; // initialize libraries - integrateDeReWo(); - initDidYouMean(); - integrateOpenGeoDB(); - integrateGeonames(); + integrateDeReWo(); + initDidYouMean(); + integrateOpenGeoDB(); + integrateGeonames(); } public static void integrateOpenGeoDB() { final File geo1 = Dictionary.GEODB1.file(); final File geo0 = Dictionary.GEODB0.file(); - if (geo1.exists()) { - if (geo0.exists()) geo0.renameTo(Dictionary.GEODB0.fileDisabled()); + if ( geo1.exists() ) { + if ( geo0.exists() ) { + geo0.renameTo(Dictionary.GEODB0.fileDisabled()); + } geoLoc.addLocalization(Dictionary.GEODB1.nickname, new OpenGeoDBLocalization(geo1, false)); return; } - if (geo0.exists()) { + if ( geo0.exists() ) { geoLoc.addLocalization(Dictionary.GEODB0.nickname, new OpenGeoDBLocalization(geo0, false)); return; } @@ -119,15 +127,17 @@ public class LibraryProvider { public static void integrateGeonames() { final File geon = Dictionary.GEON0.file(); - if (geon.exists()) { + if ( geon.exists() ) { geoLoc.addLocalization(Dictionary.GEON0.nickname, new GeonamesLocalization(geon)); return; } } public static void initDidYouMean() { - final File dymDict = new File(dictRoot, path_to_did_you_mean_dictionaries); - if (!dymDict.exists()) dymDict.mkdirs(); + final File dymDict = new File(dictRoot, path_to_did_you_mean_dictionaries); + if ( !dymDict.exists() ) { + dymDict.mkdirs(); + } dymLib = new WordCache(dymDict); } @@ -141,15 +151,17 @@ public class LibraryProvider { public static void integrateDeReWo() { // translate input files (once..) final File dymDict = new File(dictRoot, path_to_did_you_mean_dictionaries); - if (!dymDict.exists()) dymDict.mkdirs(); + if ( !dymDict.exists() ) { + dymDict.mkdirs(); + } final File derewoInput = LibraryProvider.Dictionary.DRW0.file(); final File derewoOutput = new File(dymDict, derewoInput.getName() + ".words"); - if (!derewoOutput.exists() && derewoInput.exists()) { + if ( !derewoOutput.exists() && derewoInput.exists() ) { // create the translation of the derewo file (which is easy in this case) final ArrayList derewo = loadDeReWo(derewoInput, true); try { writeWords(derewoOutput, derewo); - } catch (final IOException e) { + } catch ( final IOException e ) { Log.logException(e); } } @@ -181,14 +193,18 @@ public class LibraryProvider { private static Set sortUnique(final List list) { final Set s = new TreeSet(); - for (final String t: list) s.add(t); + for ( final String t : list ) { + s.add(t); + } return s; } private static void writeWords(final File f, final ArrayList list) throws IOException { final Set s = sortUnique(list); final PrintWriter w = new PrintWriter(new BufferedWriter(new FileWriter(f))); - for (final String t: s) w.println(t); + for ( final String t : s ) { + w.println(t); + } w.close(); } @@ -207,10 +223,10 @@ public class LibraryProvider { } */ derewoTxtEntry = zip.getInputStream(zip.getEntry("derewo-v-100000t-2009-04-30-0.1")); - } catch (final ZipException e) { + } catch ( final ZipException e ) { Log.logException(e); return list; - } catch (final IOException e) { + } catch ( final IOException e ) { Log.logException(e); return list; } @@ -221,8 +237,10 @@ public class LibraryProvider { String line; // read until text starts - while ((line = reader.readLine()) != null) { - if (line.startsWith("# -----")) break; + while ( (line = reader.readLine()) != null ) { + if ( line.startsWith("# -----") ) { + break; + } } // read empty line line = reader.readLine(); @@ -231,22 +249,32 @@ public class LibraryProvider { int p; //int c; String w; - while ((line = reader.readLine()) != null) { + while ( (line = reader.readLine()) != null ) { line = line.trim(); - p = line.indexOf(' ',0); - if (p > 0) { + p = line.indexOf(' ', 0); + if ( p > 0 ) { //c = Integer.parseInt(line.substring(p + 1)); //if (c < 1) continue; - w = (toLowerCase) ? line.substring(0, p).trim().toLowerCase() : line.substring(0, p).trim(); - if (w.length() < 4) continue; + w = + (toLowerCase) ? line.substring(0, p).trim().toLowerCase() : line + .substring(0, p) + .trim(); + if ( w.length() < 4 ) { + continue; + } list.add(w); } } reader.close(); - } catch (final IOException e) { + } catch ( final IOException e ) { Log.logException(e); } finally { - if (reader != null) try { reader.close(); } catch (final Exception e) {} + if ( reader != null ) { + try { + reader.close(); + } catch ( final Exception e ) { + } + } } return list; } @@ -256,7 +284,7 @@ public class LibraryProvider { initialize(new File(here, "DATA/DICTIONARIES")); System.out.println("dymDict-size = " + dymLib.size()); final Set r = dymLib.recommend(new StringBuilder("da")); - for (final StringBuilder s: r) { + for ( final StringBuilder s : r ) { System.out.println("$ " + s); } System.out.println("recommendations: " + r.size()); diff --git a/source/net/yacy/document/geolocalization/GeonamesLocalization.java b/source/net/yacy/document/geolocalization/GeonamesLocalization.java index 7ca149c78..735816983 100644 --- a/source/net/yacy/document/geolocalization/GeonamesLocalization.java +++ b/source/net/yacy/document/geolocalization/GeonamesLocalization.java @@ -42,7 +42,8 @@ import java.util.zip.ZipFile; import net.yacy.document.StringBuilderComparator; import net.yacy.kelondro.logging.Log; -public class GeonamesLocalization implements Localization { +public class GeonamesLocalization implements Localization +{ /* The main 'geoname' table has the following fields : @@ -68,7 +69,7 @@ public class GeonamesLocalization implements Localization { modification date : date of last modification in yyyy-MM-dd format */ - private final Map id2loc; + private final Map id2loc; private final TreeMap> name2ids; private final File file; @@ -76,17 +77,20 @@ public class GeonamesLocalization implements Localization { // this is a processing of the cities1000.zip file from http://download.geonames.org/export/dump/ this.file = file; - this.id2loc = new HashMap(); - this.name2ids = new TreeMap>(StringBuilderComparator.CASE_INSENSITIVE_ORDER); + this.id2loc = new HashMap(); + this.name2ids = + new TreeMap>(StringBuilderComparator.CASE_INSENSITIVE_ORDER); - if (file == null || !file.exists()) return; + if ( file == null || !file.exists() ) { + return; + } BufferedReader reader; try { final ZipFile zf = new ZipFile(file); final ZipEntry ze = zf.getEntry("cities1000.txt"); final InputStream is = zf.getInputStream(ze); reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); - } catch (final IOException e) { + } catch ( final IOException e ) { Log.logException(e); return; } @@ -96,84 +100,121 @@ public class GeonamesLocalization implements Localization { String line; String[] fields; Set locnames; - while ((line = reader.readLine()) != null) { - if (line.length() == 0) continue; + while ( (line = reader.readLine()) != null ) { + if ( line.length() == 0 ) { + continue; + } fields = line.split("\t"); final int id = Integer.parseInt(fields[0]); locnames = new HashSet(); locnames.add(new StringBuilder(fields[1])); locnames.add(new StringBuilder(fields[2])); - for (final String s: fields[3].split(",")) locnames.add(new StringBuilder(s)); - final Location c = new Location(Float.parseFloat(fields[5]), Float.parseFloat(fields[4]), fields[1]); + for ( final String s : fields[3].split(",") ) { + locnames.add(new StringBuilder(s)); + } + final Location c = + new Location(Float.parseFloat(fields[5]), Float.parseFloat(fields[4]), fields[1]); c.setPopulation((int) Long.parseLong(fields[14])); this.id2loc.put(id, c); - for (final StringBuilder name: locnames) { + for ( final StringBuilder name : locnames ) { List locs = this.name2ids.get(name); - if (locs == null) locs = new ArrayList(1); + if ( locs == null ) { + locs = new ArrayList(1); + } locs.add(id); this.name2ids.put(name, locs); } } - } catch (final IOException e) { + } catch ( final IOException e ) { Log.logException(e); } } + @Override public int locations() { return this.id2loc.size(); } + @Override public TreeSet find(final String anyname, final boolean locationexact) { final Set r = new HashSet(); List c; final StringBuilder an = new StringBuilder(anyname); - if (locationexact) { - c = this.name2ids.get(anyname); if (c != null) r.addAll(c); + if ( locationexact ) { + c = this.name2ids.get(an); + if ( c != null ) { + r.addAll(c); + } } else { final SortedMap> cities = this.name2ids.tailMap(an); - for (final Map.Entry> e: cities.entrySet()) { - if (StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(e.getKey(), an)) r.addAll(e.getValue()); else break; + for ( final Map.Entry> e : cities.entrySet() ) { + if ( StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(e.getKey(), an) ) { + r.addAll(e.getValue()); + } else { + break; + } } } final TreeSet a = new TreeSet(); - for (final Integer e: r) { + for ( final Integer e : r ) { final Location w = this.id2loc.get(e); - if (w != null) a.add(w); + if ( w != null ) { + a.add(w); + } } return a; } + @Override public Set recommend(final String s) { final Set a = new HashSet(); final StringBuilder an = new StringBuilder(s); - if (s.length() == 0) return a; + if ( s.length() == 0 ) { + return a; + } final SortedMap> t = this.name2ids.tailMap(an); - for (final StringBuilder r: t.keySet()) { - if (StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(r, an)) a.add(r.toString()); else break; + for ( final StringBuilder r : t.keySet() ) { + if ( StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(r, an) ) { + a.add(r.toString()); + } else { + break; + } } return a; } + @Override public Set recommend(final StringBuilder s) { final Set a = new HashSet(); - if (s.length() == 0) return a; + if ( s.length() == 0 ) { + return a; + } final SortedMap> t = this.name2ids.tailMap(s); - for (final StringBuilder r: t.keySet()) { - if (StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(r, s)) a.add(r); else break; + for ( final StringBuilder r : t.keySet() ) { + if ( StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(r, s) ) { + a.add(r); + } else { + break; + } } return a; } + @Override public String nickname() { return this.file.getName(); } + @Override public int hashCode() { return nickname().hashCode(); } + @Override public boolean equals(final Object other) { - if (!(other instanceof Localization)) return false; + if ( !(other instanceof Localization) ) { + return false; + } return nickname().equals(((Localization) other).nickname()); } } diff --git a/source/net/yacy/document/geolocalization/OpenGeoDBLocalization.java b/source/net/yacy/document/geolocalization/OpenGeoDBLocalization.java index bbd0f336b..fbf2aeadb 100644 --- a/source/net/yacy/document/geolocalization/OpenGeoDBLocalization.java +++ b/source/net/yacy/document/geolocalization/OpenGeoDBLocalization.java @@ -42,46 +42,47 @@ import java.util.zip.GZIPInputStream; import net.yacy.document.StringBuilderComparator; import net.yacy.kelondro.logging.Log; - /** - * this class loads and parses database dumps from the OpenGeoDB project - * files can be loaded from http://sourceforge.net/projects/opengeodb/files/ - * this class is used by the LibraryProvider, which expects input files inside - * DATA\DICTIONARIES\source - * - * ATTENTION: - * if this class is used, expect an extra memory usage of more than 100MB! - * - * This class will provide a super-fast access to the OpenGeoDB, - * since all request are evaluated using data in the RAM. + * this class loads and parses database dumps from the OpenGeoDB project files can be loaded from + * http://sourceforge.net/projects/opengeodb/files/ this class is used by the LibraryProvider, which expects + * input files inside DATA\DICTIONARIES\source ATTENTION: if this class is used, expect an extra memory usage + * of more than 100MB! This class will provide a super-fast access to the OpenGeoDB, since all request are + * evaluated using data in the RAM. */ -public class OpenGeoDBLocalization implements Localization { +public class OpenGeoDBLocalization implements Localization +{ - private final Map locTypeHash2locType; - private final Map id2loc; - private final Map id2locTypeHash; + private final Map locTypeHash2locType; + private final Map id2loc; + private final Map id2locTypeHash; private final TreeMap> name2ids; private final TreeMap> kfz2ids; private final Map> predial2ids; - private final Map zip2id; + private final Map zip2id; private final File file; public OpenGeoDBLocalization(final File file, final boolean lonlat) { - this.file = file; + this.file = file; this.locTypeHash2locType = new HashMap(); - this.id2loc = new HashMap(); - this.id2locTypeHash = new HashMap(); - this.name2ids = new TreeMap>(StringBuilderComparator.CASE_INSENSITIVE_ORDER); - this.kfz2ids = new TreeMap>(StringBuilderComparator.CASE_INSENSITIVE_ORDER); - this.predial2ids = new HashMap>(); - this.zip2id = new HashMap(); - - if (file == null || !file.exists()) return; + this.id2loc = new HashMap(); + this.id2locTypeHash = new HashMap(); + this.name2ids = + new TreeMap>(StringBuilderComparator.CASE_INSENSITIVE_ORDER); + this.kfz2ids = + new TreeMap>(StringBuilderComparator.CASE_INSENSITIVE_ORDER); + this.predial2ids = new HashMap>(); + this.zip2id = new HashMap(); + + if ( file == null || !file.exists() ) { + return; + } BufferedReader reader = null; try { InputStream is = new FileInputStream(file); - if (file.getName().endsWith(".gz")) is = new GZIPInputStream(is); + if ( file.getName().endsWith(".gz") ) { + is = new GZIPInputStream(is); + } reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); String line; @@ -90,16 +91,21 @@ public class OpenGeoDBLocalization implements Localization { Integer id; String h; float lon, lat; - while ((line = reader.readLine()) != null) { + while ( (line = reader.readLine()) != null ) { line = line.trim(); - if (!line.startsWith("INSERT INTO ")) continue; - if (!line.endsWith(");")) continue; + if ( !line.startsWith("INSERT INTO ") ) { + continue; + } + if ( !line.endsWith(");") ) { + continue; + } line = line.substring(12); //p = line.indexOf(' '); if (p < 0) continue; - if (line.startsWith("geodb_coordinates ")) { - line = line.substring(18 + 7);v = line.split(","); + if ( line.startsWith("geodb_coordinates ") ) { + line = line.substring(18 + 7); + v = line.split(","); v = line.split(","); - if (lonlat) { + if ( lonlat ) { lon = Float.parseFloat(v[2]); lat = Float.parseFloat(v[3]); } else { @@ -108,39 +114,49 @@ public class OpenGeoDBLocalization implements Localization { } this.id2loc.put(Integer.parseInt(v[0]), new Location(lon, lat)); } - if (line.startsWith("geodb_textdata ")) { + if ( line.startsWith("geodb_textdata ") ) { line = line.substring(15 + 7); v = line.split(","); - if (v[1].equals("500100000")) { // Ortsname + if ( v[1].equals("500100000") ) { // Ortsname id = Integer.parseInt(v[0]); h = removeQuotes(v[2]); - List l = this.name2ids.get(h); - if (l == null) l = new ArrayList(1); + List l = this.name2ids.get(new StringBuilder(h)); + if ( l == null ) { + l = new ArrayList(1); + } l.add(id); this.name2ids.put(new StringBuilder(h), l); final Location loc = this.id2loc.get(id); - if (loc != null) loc.setName(h); - } else if (v[1].equals("500400000")) { // Vorwahl + if ( loc != null ) { + loc.setName(h); + } + } else if ( v[1].equals("500400000") ) { // Vorwahl id = Integer.parseInt(v[0]); h = removeQuotes(v[2]); List l = this.predial2ids.get(h); - if (l == null) l = new ArrayList(1); + if ( l == null ) { + l = new ArrayList(1); + } l.add(id); this.predial2ids.put(h, l); - } else if (v[1].equals("400300000")) { // Ortstyp + } else if ( v[1].equals("400300000") ) { // Ortstyp id = Integer.parseInt(v[0]); h = removeQuotes(v[2]); final Integer hc = h.hashCode(); final String t = this.locTypeHash2locType.get(hc); - if (t == null) this.locTypeHash2locType.put(hc, h); + if ( t == null ) { + this.locTypeHash2locType.put(hc, h); + } this.id2locTypeHash.put(id, hc); - } else if (v[1].equals("500300000")) { // PLZ + } else if ( v[1].equals("500300000") ) { // PLZ this.zip2id.put(removeQuotes(v[2]), Integer.parseInt(v[0])); - } else if (v[1].equals("500500000")) { // KFZ-Kennzeichen + } else if ( v[1].equals("500500000") ) { // KFZ-Kennzeichen id = Integer.parseInt(v[0]); h = removeQuotes(v[2]); - List l = this.kfz2ids.get(h); - if (l == null) l = new ArrayList(1); + List l = this.kfz2ids.get(new StringBuilder(h)); + if ( l == null ) { + l = new ArrayList(1); + } l.add(id); this.kfz2ids.put(new StringBuilder(h), l); } @@ -148,93 +164,139 @@ public class OpenGeoDBLocalization implements Localization { continue; } reader.close(); - } catch (final IOException e) { + } catch ( final IOException e ) { Log.logException(e); } finally { - if (reader != null) try { reader.close(); } catch (final Exception e) {} + if ( reader != null ) { + try { + reader.close(); + } catch ( final Exception e ) { + } + } } } private static final String removeQuotes(String s) { - if (s.length() > 0 && s.charAt(0) != '\'') return s; - if (s.charAt(s.length() - 1) != '\'') return s; + if ( s.length() > 0 && s.charAt(0) != '\'' ) { + return s; + } + if ( s.charAt(s.length() - 1) != '\'' ) { + return s; + } s = s.substring(1, s.length() - 1); return s; } + @Override public int locations() { return this.id2loc.size(); } /** - * check database tables against occurrences of this entity - * the anyname - String may be one of: - * - name of a town, villa, region etc - * - zip code - * - telephone prefix - * - kfz sign + * check database tables against occurrences of this entity the anyname - String may be one of: - name of + * a town, villa, region etc - zip code - telephone prefix - kfz sign + * * @param anyname * @return */ + @Override public TreeSet find(final String anyname, final boolean locationexact) { final HashSet r = new HashSet(); List c; final StringBuilder an = new StringBuilder(anyname); - if (locationexact) { - c = this.name2ids.get(an); if (c != null) r.addAll(c); + if ( locationexact ) { + c = this.name2ids.get(an); + if ( c != null ) { + r.addAll(c); + } } else { final SortedMap> cities = this.name2ids.tailMap(an); - for (final Map.Entry> e: cities.entrySet()) { - if (StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(e.getKey(), an)) r.addAll(e.getValue()); else break; + for ( final Map.Entry> e : cities.entrySet() ) { + if ( StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(e.getKey(), an) ) { + r.addAll(e.getValue()); + } else { + break; + } + } + c = this.kfz2ids.get(an); + if ( c != null ) { + r.addAll(c); + } + c = this.predial2ids.get(anyname); + if ( c != null ) { + r.addAll(c); + } + final Integer i = this.zip2id.get(anyname); + if ( i != null ) { + r.add(i); } - c = this.kfz2ids.get(an); if (c != null) r.addAll(c); - c = this.predial2ids.get(anyname); if (c != null) r.addAll(c); - final Integer i = this.zip2id.get(anyname); if (i != null) r.add(i); } final TreeSet a = new TreeSet(); - for (final Integer e: r) { + for ( final Integer e : r ) { final Location w = this.id2loc.get(e); - if (w != null) a.add(w); + if ( w != null ) { + a.add(w); + } } return a; } /** * read the dictionary and construct a set of recommendations to a given string + * * @param s input value that is used to match recommendations * @return a set that contains all words that start with the input value */ + @Override public Set recommend(final String s) { final Set a = new HashSet(); final StringBuilder an = new StringBuilder(s); - if (s.length() == 0) return a; + if ( s.length() == 0 ) { + return a; + } final SortedMap> t = this.name2ids.tailMap(an); - for (final StringBuilder r: t.keySet()) { - if (StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(r, an)) a.add(r.toString()); else break; + for ( final StringBuilder r : t.keySet() ) { + if ( StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(r, an) ) { + a.add(r.toString()); + } else { + break; + } } return a; } + @Override public Set recommend(final StringBuilder s) { final Set a = new HashSet(); - if (s.length() == 0) return a; + if ( s.length() == 0 ) { + return a; + } final SortedMap> t = this.name2ids.tailMap(s); - for (final StringBuilder r: t.keySet()) { - if (StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(r, s)) a.add(r); else break; + for ( final StringBuilder r : t.keySet() ) { + if ( StringBuilderComparator.CASE_INSENSITIVE_ORDER.startsWith(r, s) ) { + a.add(r); + } else { + break; + } } return a; } + @Override public String nickname() { return this.file.getName(); } + @Override public int hashCode() { return nickname().hashCode(); } + @Override public boolean equals(final Object other) { - if (!(other instanceof Localization)) return false; + if ( !(other instanceof Localization) ) { + return false; + } return nickname().equals(((Localization) other).nickname()); } }