Michael Peter Christen 9 years ago
commit 8f4a341735

@ -100,6 +100,5 @@
<classpathentry kind="lib" path="lib/imageio-bmp-3.2.1.jar"/>
<classpathentry kind="lib" path="lib/jsonic-1.2.0.jar"/>
<classpathentry kind="lib" path="lib/langdetect.jar"/>
<classpathentry kind="lib" path="lib/xliff-core-1.2-1.1.jar"/>
<classpathentry kind="output" path="gen"/>
</classpath>

@ -19,7 +19,7 @@
<key>CFBundleAllowMixedLocalizations</key>
<string>true</string>
<key>CFBundleExecutable</key>
<string>startYACY.sh</string>
<string>startYACYMacOS.sh</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundlePackageType</key>

@ -0,0 +1,8 @@
#!/usr/bin/env sh
# Launcher for YaCy in a MacOS bundle :
# rely on the generic startYACY.sh, but specifies the user home relative path for YaCy data
# This data directory is set in conforming to OS X File System Programming Guide
# see : https://developer.apple.com/library/ios/documentation/FileManagement/Conceptual/FileSystemProgrammingGuide/MacOSXDirectories/MacOSXDirectories.html
"`dirname $0`"/startYACY.sh -s "'Library/Application Support/net.yacy.YaCy'"

@ -242,7 +242,6 @@
<pathelement location="${lib}/weupnp-0.1.4.jar" />
<pathelement location="${lib}/woodstox-core-asl-4.4.1.jar" />
<pathelement location="${lib}/xercesImpl.jar" />
<pathelement location="${lib}/xliff-core-1.2-1.1.jar" />
<pathelement location="${lib}/xml-apis.jar" />
<pathelement location="${lib}/xmpcore-5.1.2.jar" />
<pathelement location="${lib}/zookeeper-3.4.6.jar" />
@ -765,7 +764,8 @@
</copy>
<copy file="${addon}/YaCy.app/Contents/Info.plist" tofile="${release_mac}/YaCy.app/Contents/Info.plist" filtering="true" overwrite="true" />
<move file="${release_main}" tofile="${release_mac}/YaCy.app/Contents/MacOS" verbose="false" />
<!-- startYACY.sh will be the main entry point : we set permissions to make it an executable file -->
<!-- startYACY.sh and startYACYMacOS.sh will be the main entry points : we set permissions to make it executable files -->
<chmod file="${release_mac}/YaCy.app/Contents/MacOS/startYACYMacOS.sh" perm="755"/>
<chmod file="${release_mac}/YaCy.app/Contents/MacOS/startYACY.sh" perm="755"/>
<exec executable="hdiutil">
<arg line="create -srcfolder ${release_mac}/YaCy.app ${release}/yacy_v${releaseVersion}_${DSTAMP}_${releaseNr}.dmg"/>

@ -18,6 +18,10 @@ WORKDIR /opt
# - Compile with ant
# - remove unnecessary and size consuming .git directory
# - remove ant and git packages
# Possible alternative : copy directly your current sources an remove git clone command from the following RUN
# COPY . /opt/yacy_search_server/
RUN apt-get update && \
apt-get install -yq ant git && \
git clone https://github.com/yacy/yacy_search_server.git && \
@ -30,14 +34,17 @@ RUN apt-get update && \
# Set initial admin password : "docker" (encoded with custom yacy md5 function net.yacy.cora.order.Digest.encodeMD5Hex())
RUN sed -i "/adminAccountBase64MD5=/c\adminAccountBase64MD5=MD5:e672161ffdce91be4678605f4f4e6786" /opt/yacy_search_server/defaults/yacy.init
# Intially enable HTTPS : this is the most secure option for remote administrator authentication
RUN sed -i "/server.https=false/c\server.https=true" /opt/yacy_search_server/defaults/yacy.init
# Create user and group yacy : this user will be used to run YaCy main process
RUN adduser --system --group --no-create-home --disabled-password yacy
# Set ownership of yacy install directory to yacy user/group
RUN chown yacy:yacy -R /opt/yacy_search_server
# Expose port 8090
EXPOSE 8090
# Expose HTTP and HTTPS default ports
EXPOSE 8090 8443
# Set data volume : yacy data and configuration will persist aven after container stop or destruction
VOLUME ["/opt/yacy_search_server/DATA"]

@ -51,6 +51,10 @@ WORKDIR /opt
# - compile with apache ant
# - remove unnecessary and size consuming .git directory
# - delete git package and ant binary install
# Possible alternative : copy directly your current sources an remove git clone command from the following RUN
# COPY . /opt/yacy_search_server/
RUN apk update && \
apk add --no-cache git && \
git clone https://github.com/yacy/yacy_search_server.git && \
@ -62,14 +66,17 @@ RUN apk update && \
# Set initial admin password : "docker" (encoded with custom yacy md5 function net.yacy.cora.order.Digest.encodeMD5Hex())
RUN sed -i "/adminAccountBase64MD5=/c\adminAccountBase64MD5=MD5:e672161ffdce91be4678605f4f4e6786" /opt/yacy_search_server/defaults/yacy.init
# Intially enable HTTPS : this is the most secure option for remote administrator authentication
RUN sed -i "/server.https=false/c\server.https=true" /opt/yacy_search_server/defaults/yacy.init
# Create user and group yacy : this user will be used to run YaCy main process
RUN addgroup yacy && adduser -S -G yacy -H -D yacy
# Set ownership of yacy install directory to yacy user/group
RUN chown yacy:yacy -R /opt/yacy_search_server
# Expose port 8090
EXPOSE 8090
# Expose HTTP and HTTPS default ports
EXPOSE 8090 8443
# Set data volume : yacy data and configuration will persist aven after container stop or destruction
VOLUME ["/opt/yacy_search_server/DATA"]

@ -18,6 +18,11 @@ Using yacy_search_server/docker/Dockerfile :
cd yacy_search_server/docker
docker build .
To build the Alpine variant :
cd yacy_search_server/docker
docker build -f Dockerfile.alpine .
## Image variants
`luccioman/yacy:latest`
@ -49,12 +54,12 @@ You can retrieve the container IP address with `docker inspect`.
#### Easier to handle
docker run --name yacy -p 8090:8090 --log-opt max-size=100m --log-opt max-file=2 luccioman/yacy
docker run --name yacy -p 8090:8090 -p 8443:8443 --log-opt max-size=200m --log-opt max-file=2 luccioman/yacy
##### Options detail
* --name : allow easier management of your container (without it, docker automatically generate a new name at each startup).
* -p : map host port and container port, allowing web interface access through the usual http://localhost:8090.
* -p 8090:8090 -p 8443:8443 : map host ports to YaCy container ports, allowing web interface access through the usual http://localhost:8090 and https://localhost:8443 (you can set a different mapping, for example -p 443:8443 if you prefer to use the default HTTPS port on your host)
* --log-opt max-size : limit maximum docker log file size for this container
* --log-opt max-file : limit number of docker rotated log files for this container
@ -76,9 +81,47 @@ Note that you can list all docker volumes with :
docker volume ls
#### As background process
#### Start as background process
docker run -d luccioman/yacy
### HTTPS support
This images are default configured with HTTPS enabled, and use a default certificate stored in defaults/freeworldKeystore. You should use your own certificate. In order to do it, you can proceed as follow.
#### Self-signed certificate
A self-signed certificate will provide encrypted communications with your YaCy server, but browsers will still complain about an invalid security certificate with the error "SEC_ERROR_UNKNOWN_ISSUER". If it is sufficient for you, you can permanently add and exception to your browser.
This kind of certificate can be generated and added to your YaCy Docker container with the following :
keytool -keystore /var/lib/docker/volumes/[your_yacy_volume]/_data/SETTINGS/yacykeystore -genkey -keyalg RSA -alias yacycert
Then edit YaCy config file. For example with the nano text editor :
nano /var/lib/docker/volumes/[your_yacy_volume]/_data/SETTINGS/yacy.conf
And configure the keyStoreXXXX properties accordingly :
keyStore=/opt/yacy_search_server/DATA/SETTINGS/yacykeystore
keyStorePassword=yourpassword
#### Import an existing certificate:
Importing a certificate validated by a certification authority (CA) will ensure you have full HTTPS support with no security errors when accessing your YaCy peer. You can import an existing certificate in pkcs12 format.
First copy it to the YaCy Docker container volume :
cp [yourStore].pkcs12 /var/lib/docker/volumes/[your_yacy_volume]/_data/SETTINGS/[yourStore].pkcs12
Then edit YaCy config file. For example with the nano text editor :
nano /var/lib/docker/volumes/[your_yacy_volume]/_data/SETTINGS/yacy.conf
And configure the pkcs12XXX properties accordingly :
pkcs12ImportFile=/opt/yacy_search_server/DATA/SETTINGS/[yourStore].pkcs12
pkcs12ImportPwd=yourpassword
### Next starts
@ -109,7 +152,7 @@ OR
Create new container based on pulled image, using volume data from old container :
docker create --name [tmp-container_name] -p 8090:8090 --volumes-from=[container_name] --log-opt max-size=100m --log-opt max-file=2 luccioman/yacy:latest
docker create --name [tmp-container_name] -p 8090:8090 -p 8443:8443 --volumes-from=[container_name] --log-opt max-size=100m --log-opt max-file=2 luccioman/yacy:latest
Stop old container :

@ -2,5 +2,6 @@ yacy:
image: 'luccioman/yacy:latest'
ports:
- '8090:8090'
- '8443:8443'
restart: on-failure
autoredeploy: true

@ -231,6 +231,16 @@
<dt>Action</dt>
<dd>#(syn1Status)#<input type="submit" name="syn1Activate" class="btn btn-sm btn-primary" value="Activate" />::<input type="submit" name="syn1Deactivate" class="btn btn-sm btn-primary" value="Deactivate" />#(/syn1Status)#</dd>
</dl>
<h4>Russian Thesaurus</h4>
<p>The data was converted to the YaCy synonym file format and part of the YaCy distribution.</p>
<dl>
<dt><label>Status</label></dt>
<dd>#(syn2Status)#<div class="info">Deactivated</div>::<div class="commit">Activated</div>#(/syn2Status)#</dd>
<dt>Action</dt>
<dd>#(syn2Status)#<input type="submit" name="syn2Activate" class="btn btn-sm btn-primary" value="Activate" />::<input type="submit" name="syn2Deactivate" class="btn btn-sm btn-primary" value="Deactivate" />#(/syn2Status)#</dd>
</dl>
</fieldset>
</form>
#%env/templates/footer.template%#

@ -45,10 +45,12 @@ public class DictionaryLoader_p {
final serverObjects prop = new serverObjects(); // return variable that accumulates replacements
final File synonyms_path = new File(sb.dictionariesPath, LibraryProvider.path_to_synonym_dictionaries);
final File synonym_de_default = new File(new File(new File(sb.appPath, "addon"), "synonyms"), "openthesaurus_de_yacy");
final File synonym_de_default = new File(sb.appPath, "addon/synonyms/openthesaurus_de_yacy");
final File synonym_de_production = new File(synonyms_path, synonym_de_default.getName());
final File synonym_en_default = new File(new File(new File(sb.appPath, "addon"), "synonyms"), "mobythesaurus_en_yacy");
final File synonym_en_default = new File(sb.appPath, "addon/synonyms/mobythesaurus_en_yacy");
final File synonym_en_production = new File(synonyms_path, synonym_en_default.getName());
final File synonym_ru_default = new File(sb.appPath, "addon/synonyms/thesaurus_ru_yacy");
final File synonym_ru_production = new File(synonyms_path, synonym_ru_default.getName());
/*
* distinguish the following cases:
* - dictionary file was not loaded -> actions: load the file
@ -70,7 +72,7 @@ public class DictionaryLoader_p {
// check here only if there is no possibility synonym libraries have been activated/deactivated
prop.put("syn0Status", synonym_de_production.exists() ? 1 : 0);
prop.put("syn1Status", synonym_en_production.exists() ? 1 : 0);
prop.put("syn2Status", synonym_ru_production.exists() ? 1 : 0);
return prop;
}
@ -322,11 +324,25 @@ public class DictionaryLoader_p {
}
SynonymLibrary.init(synonyms_path);
}
if (post.containsKey("syn2Deactivate")) {
synonym_ru_production.delete();
SynonymLibrary.init(synonyms_path);
}
if (post.containsKey("syn2Activate")) {
try {
FileUtils.copy(new FileInputStream(synonym_ru_default), synonym_ru_production);
} catch (IOException e) {
ConcurrentLog.logException(e);
}
SynonymLibrary.init(synonyms_path);
}
if (post != null) {
// check here if there is a possibility synonym libraries have been activated/deactivated
prop.put("syn0Status", synonym_de_production.exists() ? 1 : 0);
prop.put("syn1Status", synonym_en_production.exists() ? 1 : 0);
prop.put("syn2Status", synonym_ru_production.exists() ? 1 : 0);
}
// check status again

@ -43,6 +43,10 @@
A change in the personal profile will create a news entry. You can see recently made changes of
profile entries on the Network page, where that profile change is visualized with a '*' beside the 'P' (profile) - selector.
</li>
<li>
Publishing of added or modified translation for the user interface. Other peers may include it in their local translation list.
To publish a translation, use the integrated <a href="Translator_p.html">translation editor</a> to add a translation and publish it afterwards.
</li>
</ul>
<p>
More news services will follow.

@ -38,6 +38,7 @@ import net.yacy.cora.order.NaturalOrder;
import net.yacy.cora.protocol.RequestHeader;
import net.yacy.cora.sorting.ConcurrentScoreMap;
import net.yacy.cora.sorting.ScoreMap;
import net.yacy.cora.util.ConcurrentLog;
import net.yacy.kelondro.index.Row;
import net.yacy.kelondro.index.Row.Entry;
import net.yacy.peers.NewsDB;
@ -258,7 +259,7 @@ public class Supporter {
urlhash = null;
}
if (urlhash==null) {
System.out.println("Supporter: bad url '" + url + "' from news record " + record.toString());
ConcurrentLog.info("Supporter", "bad url '" + url + "' from news record " + record.toString());
continue;
}
if ((vote = negativeHashes.get(urlhash)) != null) {

@ -0,0 +1,62 @@
<!DOCTYPE html>
<html>
<head>
<title>YaCy '#[clientname]#': Translation News</title>
#%env/templates/metas.template%#
</head>
<body>
#%env/templates/header.template%#
#%env/templates/submenuComputation.template%#
<h2 class="yacy">Translation News for Language #[currentlang]#</h2>
<form method="post" enctype="multipart/form-data">
<p>
You can share your local addition to translations and distribute it to other peers.
The remote peer can vote on your translation and add it to the own local translation.<br>
(#[transsize]# entries available)&nbsp;&nbsp;<input type="submit" class="btn btn-default" name="publishtranslation" value="Publish">
&nbsp;&nbsp;<small>You can check your outgoing messages <a href="News.html?page=3">here</a></small>
</p>
</form>
#(errmsg)#::<p class="error">Please activate a different language <a href='ConfigBasic.html'>here</a></p>#(/errmsg)#
#{results}#
<!-- link begin -->
<fieldset>
<table>
<tr>
<th>File:</th><th><a href="#[url]#" target="transnewsfile">#[filename]#</a></th><th>Originator</th>
</tr>
<tr>
<td>English:</td><td>#[source]#</td><td></td>
</tr>
#(existing)#::
<tr>
<td>existing</td><td class="warning">#[target]#</td><td></td>
</tr>
#(/existing)#
<tr>
<td>Translation:</td><td>#[target]#</td><td>#[peername]#</td>
</tr>
<tr><td><small>score #[score]#</small></td>
<td>&nbsp;
<a href="TransNews_p.html?voteNegative=#[refid]#" title="negative vote">
<span class="warning glyphicon glyphicon-thumbs-down"</span></a>
&nbsp;&nbsp;
<a href="TransNews_p.html?votePositive=#[refid]#&amp;filename=#[filename]#&amp;source=#[source]#&amp;target=#[target]#" title="positive vote" >
<span class="success glyphicon glyphicon-thumbs-up"></span></a>
&nbsp;&nbsp;<small>Vote on this translation. If you vote positive the translation is added to your local translation list.</small>
</td><td></td>
</tr>
</table>
</fieldset>
<!-- link end -->
#{/results}#
<p>
<br>
</p>
#%env/templates/footer.template%#
</body>
</html>

@ -0,0 +1,323 @@
// TransNews_p.java
//
// This is a part of YaCy, a peer-to-peer based web search engine
// published on http://yacy.net
//
// This file is contributed by Burkhard Buelte
//
// $LastChangedDate$
// $LastChangedRevision$
// $LastChangedBy$
//
// LICENSE
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import net.yacy.cora.protocol.RequestHeader;
import net.yacy.cora.sorting.ConcurrentScoreMap;
import net.yacy.cora.sorting.ScoreMap;
import net.yacy.cora.util.SpaceExceededException;
import net.yacy.peers.NewsDB;
import net.yacy.peers.NewsPool;
import net.yacy.search.Switchboard;
import net.yacy.server.serverObjects;
import net.yacy.server.serverSwitch;
import net.yacy.utils.crypt;
import net.yacy.utils.translation.TranslationManager;
public class TransNews_p {
public static serverObjects respond(final RequestHeader header, final serverObjects post, final serverSwitch env) {
final Switchboard sb = (Switchboard) env;
final serverObjects prop = new serverObjects();
String currentlang = sb.getConfig("locale.language", "default");
prop.put("currentlang", currentlang);
if ("default".equals(currentlang) || "browser".equals(currentlang)) {
prop.put("errmsg", 1); // msg: activate diff lng
prop.put("transsize", 0);
return prop;
} else {
prop.put("errmsg", 0);
}
TranslationManager transMgr = new TranslationManager();
File locallangFile = transMgr.getScratchFile(new File(currentlang + ".lng"));
Map<String, Map<String, String>> localTrans = transMgr.loadTranslationsLists(locallangFile);
// calculate size of local translations list
int size = 0;
for (Map<String, String> lst : localTrans.values()) {
size += lst.size();
}
prop.put("transsize", size);
// read voting
if ((post != null) && post.containsKey("publishtranslation")) {
Iterator<String> filenameit = localTrans.keySet().iterator();
while (filenameit.hasNext()) {
String file = filenameit.next();
Map<String, String> tmptrans = localTrans.get(file);
for (String sourcetxt : tmptrans.keySet()) {
String targettxt = tmptrans.get(sourcetxt);
if (targettxt != null && !targettxt.isEmpty()) {
boolean sendit = true;
// check if already published (in newsPool)
Iterator<NewsDB.Record> it = sb.peers.newsPool.recordIterator(NewsPool.INCOMING_DB);
while (it.hasNext()) {
NewsDB.Record rtmp = it.next();
if (rtmp == null) {
continue;
}
if (NewsPool.CATEGORY_TRANSLATION_ADD.equals(rtmp.category())) {
String tmplng = rtmp.attribute("language", null);
String tmpfile = rtmp.attribute("file", null);
String tmpsource = rtmp.attribute("source", null);
//String tmptarget = rtmp.attribute("target", null);
// if news with file and source exist (maybe from other peer) - skip sending another msg (to avoid confusion)
if ((tmplng != null && tmplng.equals(currentlang)) && (tmpfile != null && tmpfile.equals(file))
&& (tmpsource != null && tmpsource.equals(sourcetxt))) {
sendit = false;
break;
}
}
}
if (sendit) {
final HashMap<String, String> map = new HashMap<String, String>();
map.put("language", currentlang);
map.put("file", file);
map.put("source", sourcetxt);
map.put("target", targettxt);
sb.peers.newsPool.publishMyNews(sb.peers.mySeed(), NewsPool.CATEGORY_TRANSLATION_ADD, map);
}
}
}
}
}
String refid;
if ((post != null) && ((refid = post.get("voteNegative", null)) != null)) {
// make new news message with voting
if (!sb.isRobinsonMode()) {
final HashMap<String, String> map = new HashMap<String, String>();
map.put("language", currentlang);
map.put("file", crypt.simpleDecode(post.get("filename", "")));
map.put("source", crypt.simpleDecode(post.get("source", "")));
map.put("target", crypt.simpleDecode(post.get("target", "")));
map.put("vote", "negative");
map.put("refid", refid);
sb.peers.newsPool.publishMyNews(sb.peers.mySeed(), NewsPool.CATEGORY_TRANSLATION_VOTE_ADD, map);
try {
sb.peers.newsPool.moveOff(NewsPool.INCOMING_DB, refid);
} catch (IOException | SpaceExceededException ex) {
}
}
}
if ((post != null) && ((refid = post.get("votePositive", null)) != null)) {
final String filename = post.get("filename");
File lngfile = new File(sb.getAppPath("locale.source", "locales"), currentlang + ".lng");
transMgr = new TranslationManager(lngfile); // load full language for check if entry is new (globally)
if (transMgr.addTranslation(filename, post.get("source"), post.get("target"))) {
// add to local translation extension
transMgr.addTranslation(localTrans, filename, post.get("source"), post.get("target"));
transMgr.saveAsLngFile(currentlang, locallangFile, localTrans); // save local-trans to local-file
transMgr.translateFile(filename); // ad-hoc translate file with new/added text
} // TODO: shall we post voting if translation is not new ?
// make new news message with voting
final HashMap<String, String> map = new HashMap<String, String>();
map.put("language", currentlang);
map.put("file", crypt.simpleDecode(filename));
map.put("source", crypt.simpleDecode(post.get("source", "")));
map.put("target", crypt.simpleDecode(post.get("target", "")));
map.put("vote", "positive");
map.put("refid", refid);
sb.peers.newsPool.publishMyNews(sb.peers.mySeed(), NewsPool.CATEGORY_TRANSLATION_VOTE_ADD, map);
try {
sb.peers.newsPool.moveOff(NewsPool.INCOMING_DB, refid);
} catch (IOException | SpaceExceededException ex) {
}
}
// create Translation voting list
final HashMap<String, Integer> negativeHashes = new HashMap<String, Integer>(); // a mapping from an url hash to Integer (count of votes)
final HashMap<String, Integer> positiveHashes = new HashMap<String, Integer>(); // a mapping from an url hash to Integer (count of votes)
accumulateVotes(sb, negativeHashes, positiveHashes, NewsPool.INCOMING_DB);
final ScoreMap<String> ranking = new ConcurrentScoreMap<String>(); // score cluster for url hashes
final HashMap<String, NewsDB.Record> translation = new HashMap<String, NewsDB.Record>(); // a mapping from an url hash to a kelondroRow.Entry with display properties
accumulateTranslations(sb, translation, ranking, negativeHashes, positiveHashes, NewsPool.INCOMING_DB);
// read out translation-news array and create property entries
final Iterator<String> k = ranking.keys(false);
int i = 0;
NewsDB.Record row;
String filename;
String source;
String target;
while (k.hasNext()) {
refid = k.next();
if (refid == null) {
continue;
}
row = translation.get(refid);
if (row == null) {
continue;
}
String lang = row.attribute("language", null);
filename = row.attribute("file", null);
source = row.attribute("source", null);
target = row.attribute("target", null);
if ((lang == null) || (filename == null) || (source == null) || (target == null)) {
continue;
}
if (!lang.equals(currentlang)) continue;
String existingtarget = null; //transMgr.getTranslation(filename, source);
Map<String, String> tmpMap = localTrans.get(filename);
if (tmpMap != null) {
existingtarget = tmpMap.get(source);
}
boolean altexist = existingtarget != null && !target.isEmpty() && !existingtarget.isEmpty() && !existingtarget.equals(target);
prop.put("results_" + i + "_refid", refid);
prop.put("results_" + i + "_url", filename); // url to local file
prop.put("results_" + i + "_targetlanguage", lang);
prop.put("results_" + i + "_filename", filename);
prop.putHTML("results_" + i + "_source", source);
prop.putHTML("results_" + i + "_target", target);
prop.put("results_" + i + "_existing", altexist);
prop.putHTML("results_" + i + "_existing_target", existingtarget);
prop.put("results_" + i + "_score", ranking.get(refid));
prop.put("results_" + i + "_peername", sb.peers.get(row.originator()).getName());
i++;
if (i >= 50) {
break;
}
}
prop.put("results", i);
return prop;
}
private static void accumulateVotes(final Switchboard sb, final HashMap<String, Integer> negativeHashes, final HashMap<String, Integer> positiveHashes, final int dbtype) {
final int maxCount = Math.min(1000, sb.peers.newsPool.size(dbtype));
NewsDB.Record newsrecord;
final Iterator<NewsDB.Record> recordIterator = sb.peers.newsPool.recordIterator(dbtype);
int j = 0;
while ((recordIterator.hasNext()) && (j++ < maxCount)) {
newsrecord = recordIterator.next();
if (newsrecord == null) {
continue;
}
if (newsrecord.category().equals(NewsPool.CATEGORY_TRANSLATION_VOTE_ADD)) {
final String refid = newsrecord.attribute("refid", "");
final String vote = newsrecord.attribute("vote", "");
final int factor = ((dbtype == NewsPool.OUTGOING_DB) || (dbtype == NewsPool.PUBLISHED_DB)) ? 2 : 1;
if (vote.equals("negative")) {
final Integer i = negativeHashes.get(refid);
if (i == null) {
negativeHashes.put(refid, Integer.valueOf(factor));
} else {
negativeHashes.put(refid, Integer.valueOf(i.intValue() + factor));
}
}
if (vote.equals("positive")) {
final Integer i = positiveHashes.get(refid);
if (i == null) {
positiveHashes.put(refid, Integer.valueOf(factor));
} else {
positiveHashes.put(refid, Integer.valueOf(i.intValue() + factor));
}
}
}
}
}
private static void accumulateTranslations(
final Switchboard sb,
final HashMap<String, NewsDB.Record> translationmsg, final ScoreMap<String> ranking,
final HashMap<String, Integer> negativeHashes, final HashMap<String, Integer> positiveHashes, final int dbtype) {
final int maxCount = Math.min(1000, sb.peers.newsPool.size(dbtype));
NewsDB.Record newsrecord;
final Iterator<NewsDB.Record> recordIterator = sb.peers.newsPool.recordIterator(dbtype);
int j = 0;
String refid = "";
String targetlanguage ="";
String filename="";
String source="";
String target="";
int score = 0;
Integer vote;
while ((recordIterator.hasNext()) && (j++ < maxCount)) {
newsrecord = recordIterator.next();
if (newsrecord == null) {
continue;
}
if ((newsrecord.category().equals(NewsPool.CATEGORY_TRANSLATION_ADD))
&& ((sb.peers.get(newsrecord.originator())) != null)) {
refid = newsrecord.id();
targetlanguage = newsrecord.attribute("language", "");
filename = newsrecord.attribute("file", "");
source = newsrecord.attribute("source", "");
target = newsrecord.attribute("target", "");
if (refid.isEmpty() || targetlanguage.isEmpty() || filename.isEmpty() || source.isEmpty() || target.isEmpty()) {
continue;
}
score = 0;
}
// add/subtract votes and write record
if ((vote = negativeHashes.get(refid)) != null) {
score -= vote.intValue();
}
if ((vote = positiveHashes.get(refid)) != null) {
score += vote.intValue();
}
// consider double-entries
if (translationmsg.containsKey(refid)) {
ranking.inc(refid, score);
} else {
ranking.set(refid, score);
translationmsg.put(refid, newsrecord);
}
}
}
}

@ -17,7 +17,7 @@
<legend>
<label>UI Translation</label>
</legend>
<p>Target Language: <b>#[targetlang]#</b></p><p class="error">#[errmsg]#</p>
<p>Target Language: <b>#[targetlang]#</b></p> #(errmsg)#::<p class="error">activate a different language <a href='ConfigBasic.html'>here</a></p>#(/errmsg)#
<label for="sourcefile">Source File</label>
<select name="sourcefile" onchange="submit();">
#{filelist}#
@ -46,7 +46,7 @@
</fieldset>
</form>
<p>Check for remote translation proposals and/or share your own added translations <a href="TransNews_p.html">Translation News</a></p>
#%env/templates/footer.template%#
</body>
</html>

@ -29,7 +29,7 @@ import net.yacy.search.SwitchboardConstants;
import net.yacy.server.serverObjects;
import net.yacy.server.serverSwitch;
import net.yacy.server.servletProperties;
import net.yacy.utils.translation.CreateTranslationMasters;
import net.yacy.utils.translation.TranslationManager;
public class Translator_p {
@ -41,20 +41,20 @@ public class Translator_p {
String langcfg = sb.getConfig("locale.language", "default");
prop.put("targetlang", langcfg);
if ("default".equals(langcfg) || "browser".equals(langcfg)) {
prop.put("errmsg", "activate a different language");
prop.put("errmsg", 1); // msg: activate diff lng
return prop;
} else {
prop.put("errmsg", "");
prop.put("errmsg", 0);
}
File lngfile = new File(sb.getAppPath("locale.source", "locales"), langcfg + ".lng");
CreateTranslationMasters ctm = new CreateTranslationMasters(/*new File ("locales","master.lng.xlf")*/);
TranslationManager localTransMgr = new TranslationManager(/*new File ("locales","master.lng.xlf")*/);
File masterxlf = new File(sb.getAppPath("locale.source", "locales"), "master.lng.xlf");
if (!masterxlf.exists()) ctm.createMasterTranslationLists(masterxlf);
Map<String, Map<String, String>> origTrans = ctm.joinMasterTranslationLists(masterxlf, lngfile);
final File locallngfile = ctm.getScratchFile(lngfile);
Map<String, Map<String, String>> localTrans = ctm.loadTranslationsLists(locallngfile); // TODO: this will read file twice
if (!masterxlf.exists()) localTransMgr.createMasterTranslationLists(masterxlf);
Map<String, Map<String, String>> origTrans = localTransMgr.joinMasterTranslationLists(masterxlf, lngfile);
final File locallngfile = localTransMgr.getScratchFile(lngfile);
Map<String, Map<String, String>> localTrans = localTransMgr.loadTranslationsLists(locallngfile); // TODO: this will read file twice
int i = 0;
if (origTrans.size() > 0) {
String filename = origTrans.keySet().iterator().next();
@ -114,7 +114,7 @@ public class Translator_p {
if (i == textlistid && post != null) {
if (editapproved) { // switch already translated in edit mode by copying to local translation
// not saved here as not yet modified/approved
ctm.addTranslation(localTrans, filename, sourcetext, targettxt);
localTransMgr.addTranslation(localTrans, filename, sourcetext, targettxt);
} else {
String t = post.get("targettxt" + Integer.toString(textlistid));
// correct common partial html markup (part of text identification for words also used as html parameter)
@ -125,7 +125,7 @@ public class Translator_p {
targettxt = t;
// add changes to original (for display) and local (for save)
origTextList.put(sourcetext, targettxt);
changed = ctm.addTranslation(localTrans, filename, sourcetext, targettxt);
changed = localTransMgr.addTranslation(localTrans, filename, sourcetext, targettxt);
}
}
prop.putHTML("textlist_" + i + "_sourcetxt", sourcetext);
@ -138,7 +138,7 @@ public class Translator_p {
changed = true;
}
if (changed) {
ctm.saveAsLngFile(langcfg, locallngfile, localTrans);
localTransMgr.saveAsLngFile(langcfg, locallngfile, localTrans);
// adhoc translate this file
// 1. get/calc the path
final String htRootPath = env.getConfig(SwitchboardConstants.HTROOT_PATH, SwitchboardConstants.HTROOT_PATH_DEFAULT);
@ -147,7 +147,7 @@ public class Translator_p {
// get absolute file by adding relative filename from translationlist
final File sourceFile = new File(sourceDir, filename);
final File destFile = new File(destDir, filename);
ctm.translateFile(sourceFile, destFile, origTextList); // do the translation
localTransMgr.translateFile(sourceFile, destFile, origTextList); // do the translation
}
}
prop.put("textlist", i);

@ -33,6 +33,7 @@
<ul class="SubMenu">
<li><a href="Surftips.html" class="MenuItemLink">Surftips</a></li>
<li><a href="Wiki.html?display=1" class="MenuItemLink">Local Peer Wiki</a></li>
<li><a href="TransNews_p.html" class="MenuItemLink">UI Translations</a></li>
</ul>
</div>
</div>

@ -57,12 +57,13 @@ public final class hello {
final serverObjects prop = new serverObjects();
final long start = System.currentTimeMillis();
prop.put("message", "none");
final String clientip = header.get(HeaderFramework.CONNECTION_PROP_CLIENTIP, "<unknown>"); // read an artificial header addendum
String clientip = header.get(HeaderFramework.CONNECTION_PROP_CLIENTIP); // read an artificial header addendum
//ConcurrentLog.info("**hello-DEBUG**", "client request from = " + clientip);
final InetAddress ias = Domains.dnsResolve(clientip);
long time = System.currentTimeMillis();
final long time_dnsResolve = System.currentTimeMillis() - time;
if (ias == null) {
if (clientip == null) clientip = "<unknown>";
Network.log.info("hello/server: failed contacting seed; clientip not resolvable (clientip=" + clientip + ", time_dnsResolve=" + time_dnsResolve + ")");
prop.put("message", "cannot resolve your IP from your reported location " + clientip);
return prop;

@ -380,7 +380,9 @@ public final class search {
// prepare reference hints
final long timer = System.currentTimeMillis();
final ScoreMap<String> topicNavigator = sb.index.connectedRWI() ? theSearch.getTopics(5, 100) : new ConcurrentScoreMap<String>();
//final ScoreMap<String> topicNavigator = sb.index.connectedRWI() ? theSearch.getTopics(5, 100) : new ConcurrentScoreMap<String>();
final ScoreMap<String> topicNavigator = theSearch.getTopics(); // as there is currently no index interaction in getTopics(), we can use it by default
final StringBuilder refstr = new StringBuilder(6000);
final Iterator<String> navigatorIterator = topicNavigator.keys(false);
int i = 0;

Binary file not shown.

@ -97,9 +97,9 @@ Add new pattern:==添加新规则:
"Add URL pattern"=="添加URL规则"
The right '*', after the '/', can be replaced by a <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">regex</a>.== 在 '/' 后边的 '*' ,可用<a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">正则表达式</a>表示.
domain.net/fullpath<==domain.net/绝对路径<
>domain.net/*<==>domain.net/*<
*.domain.net/*<==*.domain.net/*<
*.sub.domain.net/*<==*.sub.domain.net/*<
#>domain.net/*<==>domain.net/*<
#*.domain.net/*<==*.domain.net/*<
#*.sub.domain.net/*<==*.sub.domain.net/*<
#sub.domain.*/*<==sub.domain.*/*<
#domain.*/*<==domain.*/*<
a complete <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">regex</a> (slow)==一个完整的<a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">正则表达式</a> (慢)
@ -641,7 +641,7 @@ Show Information Links for each Search Result Entry==显示搜索结果的链接
>Date&==>日期&
>Size&==>大小&
>Metadata&==>元数据&
>Parser&==>Parser&
#>Parser&==>Parser&
>Pictures==>图像
Default Pop-Up Page<==默认弹出页面<
>Status Page==>状态页面
@ -1563,7 +1563,7 @@ Delete==删除
#File: IndexImport_p.html
#---------------------------
YaCy '#[clientname]#': Index Import==YaCy '#[clientname]#': Index Import
#YaCy '#[clientname]#': Index Import==YaCy '#[clientname]#': Index Import
#Crawling Queue Import==Crawling Puffer Import
Index DB Import==导入索引数据
The local index currently consists of (at least) #[wcount]# reverse word indexes and #[ucount]# URL references.==本地索引当前至少有 #[wcount]# 个关键字索引和 #[ucount]# 个URL关联.
@ -1580,7 +1580,7 @@ Always do a backup of your source and destination database before starting to us
Currently running jobs==当前运行任务
Job Type==任务类型
>Path==>路径
Status==Status
#Status==Status
Elapsed<br />Time==已用<br />时间
Time<br />Left==剩余<br />时间
Abort Import==停止
@ -1607,7 +1607,7 @@ The assortment directory containing parts of the word index.==分类目录中含
The words directory containing parts of the word index.==关键字目录中含有部分关键字索引.
The assortment file that should be imported.==需要导入分类文件.
The assortment file must have the postfix==分类文件一定要有后缀名
.db".==.db".
#.db".==.db".
If you would like to import an assortment file from the <tt>PLASMADBACLUSTERABKP</tt>==如果您想从 <tt>PLASMADBACLUSTERABKP</tt> 中导入分类文件,
you have to rename it first.==则须先重命名.
>Notes:==>注意:
@ -1869,7 +1869,7 @@ Search for a peername (RegExp allowed)==搜索peer名称(允许正则表达式)
"Search"=="搜索"
Name==名称
Address==地址
Hash==Hash
#Hash==Hash
Type==类型
Release/<br/>SVN==YaCy版本/<br/>SVN
Last<br/>Seen==最后<br/>上线
@ -2068,7 +2068,7 @@ Table RAM Index:==Table使用内存:
>Key==>关键字
>Value==>值
#FlexTable RAM Index:==FlexTabelle RAM Index:
Table</td>==Table</td>
#Table</td>==Table</td>
Chunk Size<==块大小<
#Count</td>==Anzahl</td>
Used Memory<==已用内存<
@ -2755,7 +2755,7 @@ Please go to the <a href="ConfigAccounts_p.html">User Administration</a> page an
You don't have the correct access right to perform this task.==无执行此任务权限.
Please log in.==请登录.
You can now go back to the <a href="Settings_p.html">Settings</a> page if you want to make more changes.==您现在可以返回<a href="Settings_p.html">设置</a>页面进行详细设置.
See you soon!==See you soon!
#See you soon!==See you soon!
Just a moment, please!==请稍候.
Application will terminate after working off all scheduled tasks.==程序在所有任务完成后将停止,
Then YaCy will restart.==然后YaCy会重新启动.
@ -3136,7 +3136,7 @@ This table contains a short description of the tags that can be used in the Wiki
of YaCy. For a more detailed description visit the==详情请见
#YaCy Wiki==YaCy Wiki
Description==描述
=headline===headline
#=headline===headline
These tags create headlines. If a page has three or more headlines, a table of content will be created automatically.==此标记标识标题内容. 如果页面有多于三个标题, 则会自动创建一个表格.
Headlines of level 1 will be ignored in the table of content.==一级标题.
#text==Text
@ -3144,19 +3144,19 @@ These tags create stressed texts. The first pair emphasizes the text (most brows
the second one emphazises it more strongly (i.e. bold) and the last tags create a combination of both.==第二对用粗体表示, 第三对为两者的联合.
Text will be displayed <span class="strike">stricken through</span>.==文本内容以<span class="strike">删除线</span>表示.
Lines will be indented. This tag is supposed to mark citations, but may as well be used for styling purposes.==缩进内容, 此标记主要用于引用, 也能用于标识样式.
point==point
#point==point
These tags create a numbered list.==此标记用于有序列表.
something<==something<
another thing==another thing
and yet another==and yet another
something else==something else
#something<==something<
#another thing==another thing
#and yet another==and yet another
#something else==something else
These tags create an unnumbered list.==用于创建无序列表.
word==word
:definition==:definition
#word==word
#:definition==:definition
These tags create a definition list.==用于创建定义列表.
This tag creates a horizontal line.==创建水平线.
pagename==pagename
description]]==description]]
#pagename==pagename
#description]]==description]]
This tag creates links to other pages of the wiki.==创建到其他wiki页面的链接.
This tag displays an image, it can be aligned left, right or center.==显示图片, 可设置左对齐, 右对齐和居中.
These tags create a table, whereas the first marks the beginning of the table, the second starts==用于创建表格, 第一个标记为表格开头, 第二个为换行,

@ -1212,8 +1212,14 @@ Category==Categorie
Received==Reçu
Distributed==Distribu&eacute;
Attributes==Attributs
"#(page)#::Process Selected News::Delete Selected News::Abort Publication of Selected News::Delete Selected News#(/page)#"==#(page)#::Traiter les nouvelles s&eacute;lectionn&eacute;es::Supprimer les nouvelles s&eacute;lectionn&eacute;es::Annuler la publication des nouvelles s&eacute;lectionn&eacute;es::Supprimer les nouvelles s&eacute;lection&eacute;es#(/page)#
"#(page)#::Process All News::Delete All News::Abort Publication of All News::Delete All News#(/page)#"==#(page)#::Traiter toutes les nouvelles::Supprimer toutes les nouvelles::Annuler la publication de toutes les nouvelles::Supprimer toutes les nouvelles#(/page)#
Process Selected News==Traiter les nouvelles s&eacute;lectionn&eacute;es
Delete Selected News==Supprimer les nouvelles s&eacute;lectionn&eacute;es
Abort Publication of Selected News==Annuler la publication des nouvelles s&eacute;lectionn&eacute;es
Delete Selected News==Supprimer les nouvelles s&eacute;lection&eacute;es
Process All News==Traiter toutes les nouvelles
Delete All News==Supprimer toutes les nouvelles
Abort Publication of All News==Annuler la publication de toutes les nouvelles
Delete All News==Supprimer toutes les nouvelles
#-----------------------------
#File: Performance_p.html

@ -67,8 +67,8 @@ File:==Αρχείο:
#File: Bookmarks.html
#---------------------------
YaCy '#[clientname]#': Bookmarks==YaCy '#[clientname]#': Bookmarks
<h2>Bookmarks==<h2>Bookmarks
#YaCy '#[clientname]#': Bookmarks==YaCy '#[clientname]#': Bookmarks
#<h2>Bookmarks==<h2>Bookmarks
Add Bookmark==Προσθήκη Σελειδοδείκτη (Bookmark)
Edit Bookmark==Τροποποίηση Σελειδοδείκτη (Bookmark)
#URL:==URL:

@ -118,8 +118,8 @@ Waiting for new request nr.==In attesa della nuova richiesta Nr.
#File: CookieMonitorIncoming_p.html
#---------------------------
Incoming Cookies Monitor==Incoming Cookies Monitor
Cookie Monitor: Incoming Cookies==Cookie Monitor: Incoming Cookies
#Incoming Cookies Monitor==Incoming Cookies Monitor
#Cookie Monitor: Incoming Cookies==Cookie Monitor: Incoming Cookies
This is a list of Cookies that a web server has sent to clients of the YaCy Proxy:==Questa &egrave; una lista di Cookies che il server ha mnadato hai client dello YaCy Proxy:
Showing==Mostra
entries from a total of==le entrate per un totale di

@ -153,9 +153,9 @@ Add new pattern:==新規のパターンを追加する:
The right '*', after the '/', can be replaced by a=='/' の後の '*' は次のもので置き換える事ができます
>regular expression<==>正規表現<
domain.net/fullpath<==domain.net/フルパス<
>domain.net/*<==>domain.net/*<
*.domain.net/*<==*.domain.net/*<
*.sub.domain.net/*<==*.sub.domain.net/*<
#>domain.net/*<==>domain.net/*<
#*.domain.net/*<==*.domain.net/*<
#*.sub.domain.net/*<==*.sub.domain.net/*<
#sub.domain.*/*<==sub.domain.*/*<
#domain.*/*<==domain.*/*<
a complete <==完全な <
@ -665,7 +665,7 @@ Manual System Update==手動でのシステムの更新
Current installed Release==現在のインストールされているリリース
Available Releases==利用可能なリリース
>changelog<==>変更ログ<
> and <==> and <
#> and <==> and <
> RSS feed<==> RSS フィード<
(unsigned)==(署名無し)
(signed)==(署名有り)
@ -979,12 +979,12 @@ Configuration of a RSS Search==RSS検索の構成
#---------------------------
>Messages==>メッセージ
Date</td>==日時</td>
From</td>==From</td>
To</td>==To</td>
#From</td>==From</td>
#To</td>==To</td>
>Subject==>件名
Action==動作
From:==From:
To:==To:
#From:==From:
#To:==To:
Date:==日時:
#Subject:==件名:
>view==>見る
@ -1442,7 +1442,7 @@ e="Search"==e="検索"
Search Page==検索ページ
This search result can also be retrieved as RSS/<a href="http://www.opensearch.org" target="_blank">opensearch</a> output.==この検索結果はRSS/<a href="http://www.opensearch.org">opensearch</a>の出力として取得する事もできます.
The query format is similar to==クエリーの形式は次に似ています
SRU==SRU
#SRU==SRU
Click the API icon to see an example call to the search rss API.==rss APIを検索する為のエグザンプル コールを見る為にはAPI アイコンをクリックして下さい.
To see a list of all APIs, please visit the==全てのAPIの一覧を見る為には, どうぞ次を訪問して下さい
API wiki page==API ウィキページ

@ -1069,6 +1069,27 @@
<trans-unit id="33f6ce0e" xml:space="preserve" approved="no" translate="yes">
<source>Select a language for the interface</source>
</trans-unit>
<trans-unit id="c0286918" xml:space="preserve" approved="no" translate="yes">
<source>Deutsch</source>
</trans-unit>
<trans-unit id="1c8e797f" xml:space="preserve" approved="no" translate="yes">
<source>Fran&amp;ccedil;ais</source>
</trans-unit>
<trans-unit id="66bbf57f" xml:space="preserve" approved="no" translate="yes">
<source>&amp;#27721;&amp;#35821;/&amp;#28450;&amp;#35486</source>
</trans-unit>
<trans-unit id="cde4355b" xml:space="preserve" approved="no" translate="yes">
<source>&amp;#1056;&amp;#1091;&amp;#1089;&amp;#1089;&amp;#1082;&amp;#1080;&amp;#1081;</source>
</trans-unit>
<trans-unit id="3b7bf732" xml:space="preserve" approved="no" translate="yes">
<source>&amp;#1059;&amp;#1082;&amp;#1088;&amp;#1072;&amp;#1111;&amp;#1085;&amp;#1089;&amp;#1100;&amp;#1082;&amp;#1072;</source>
</trans-unit>
<trans-unit id="bb2f569d" xml:space="preserve" approved="no" translate="yes">
<source>&amp;#2361;&amp;#2367;&amp;#2344;&amp;#2381;&amp;#2342;&amp;#2368;</source>
</trans-unit>
<trans-unit id="54e2ea5e" xml:space="preserve" approved="no" translate="yes">
<source>&amp;#26085;&amp;#26412;&amp;#35486;</source>
</trans-unit>
<trans-unit id="9a6fa219" xml:space="preserve" approved="no" translate="yes">
<source>Use Case: what do you want to do with YaCy:</source>
</trans-unit>
@ -5945,6 +5966,21 @@
<trans-unit id="49006831" xml:space="preserve" approved="no" translate="yes">
<source>profile entries on the Network page, where that profile change is visualized with a '*' beside the 'P' (profile) - selector.</source>
</trans-unit>
<trans-unit id="80e8551f" xml:space="preserve" approved="no" translate="yes">
<source>Publishing of added or modified translation for the user interface.</source>
</trans-unit>
<trans-unit id="aff2f3ce" xml:space="preserve" approved="no" translate="yes">
<source>Other peers may include it in their local translation list.</source>
</trans-unit>
<trans-unit id="304f12eb" xml:space="preserve" approved="no" translate="yes">
<source>To publish a translation, use the integrated</source>
</trans-unit>
<trans-unit id="f7855dbc" xml:space="preserve" approved="no" translate="yes">
<source>translation editor</source>
</trans-unit>
<trans-unit id="7e95942a" xml:space="preserve" approved="no" translate="yes">
<source>to add a translation and publish it afterwards.</source>
</trans-unit>
<trans-unit id="ac7ecc34" xml:space="preserve" approved="no" translate="yes">
<source>Above you can see four menues:</source>
</trans-unit>
@ -5987,6 +6023,24 @@
<trans-unit id="8eff8577" xml:space="preserve" approved="no" translate="yes">
<source>Attributes</source>
</trans-unit>
<trans-unit id="8ae5c927" xml:space="preserve" approved="no" translate="yes">
<source>Process Selected News</source>
</trans-unit>
<trans-unit id="d40fbba3" xml:space="preserve" approved="no" translate="yes">
<source>Delete Selected News</source>
</trans-unit>
<trans-unit id="43ac9953" xml:space="preserve" approved="no" translate="yes">
<source>Abort Publication of Selected News</source>
</trans-unit>
<trans-unit id="49ff88e3" xml:space="preserve" approved="no" translate="yes">
<source>Process All News</source>
</trans-unit>
<trans-unit id="6fcef8e7" xml:space="preserve" approved="no" translate="yes">
<source>Delete All News</source>
</trans-unit>
<trans-unit id="30aa4d37" xml:space="preserve" approved="no" translate="yes">
<source>Abort Publication of All News</source>
</trans-unit>
<trans-unit id="8c39153f" xml:space="preserve" approved="no" translate="yes">
<source>"#(page)#::Process Selected News::Delete Selected News::Abort Publication of Selected News::Delete Selected News#(/page)#"</source>
</trans-unit>
@ -6800,6 +6854,30 @@
<trans-unit id="1ba97b50" xml:space="preserve" approved="no" translate="yes">
<source>"Re-Set to default"</source>
</trans-unit>
<trans-unit id="8410369e" xml:space="preserve" approved="no" translate="yes">
<source>&gt;Filter Query&lt;</source>
</trans-unit>
<trans-unit id="78033f39" xml:space="preserve" approved="no" translate="yes">
<source>The Filter Query is attached to every query.</source>
</trans-unit>
<trans-unit id="70b334ee" xml:space="preserve" approved="no" translate="yes">
<source>Use this to statically add a selection criteria to reduce the set of results.</source>
</trans-unit>
<trans-unit id="c227ca00" xml:space="preserve" approved="no" translate="yes">
<source>Example: "http_unique_b:true AND www_unique_b:true" will filter out all results where urls appear also with/without http(s) and/or with/without 'www.' prefix.</source>
</trans-unit>
<trans-unit id="4112ab05" xml:space="preserve" approved="no" translate="yes">
<source>To find appropriate fields for this query, see the</source>
</trans-unit>
<trans-unit id="7838433d" xml:space="preserve" approved="no" translate="yes">
<source>YaCy Solr Schema</source>
</trans-unit>
<trans-unit id="849166a5" xml:space="preserve" approved="no" translate="yes">
<source>Warning: bad expressions here will cause that you don't have any search result!</source>
</trans-unit>
<trans-unit id="47e46c2" xml:space="preserve" approved="no" translate="yes">
<source>"Set Filter Query"</source>
</trans-unit>
<trans-unit id="14f04b0f" xml:space="preserve" approved="no" translate="yes">
<source>&gt;Boost Query&lt;</source>
</trans-unit>
@ -8621,6 +8699,65 @@
</body>
</file>
<file original="TransNews_p.html" source-language="en" target-language="aa" datatype="html">
<body>
<trans-unit id="d0ae4d2d" xml:space="preserve" approved="no" translate="yes">
<source>Translation News for Language</source>
</trans-unit>
<trans-unit id="65d34722" xml:space="preserve" approved="no" translate="yes">
<source>Translation News</source>
</trans-unit>
<trans-unit id="a8b87046" xml:space="preserve" approved="no" translate="yes">
<source>You can share your local addition to translations and distribute it to other peers.</source>
</trans-unit>
<trans-unit id="cc5facc1" xml:space="preserve" approved="no" translate="yes">
<source>The remote peer can vote on your translation and add it to the own local translation.</source>
</trans-unit>
<trans-unit id="28e1bf39" xml:space="preserve" approved="no" translate="yes">
<source>entries available</source>
</trans-unit>
<trans-unit id="20c2735" xml:space="preserve" approved="no" translate="yes">
<source>"Publish"</source>
</trans-unit>
<trans-unit id="929c113c" xml:space="preserve" approved="no" translate="yes">
<source>You can check your outgoing messages</source>
</trans-unit>
<trans-unit id="6fb5a4ce" xml:space="preserve" approved="no" translate="yes">
<source>&gt;here&lt;</source>
</trans-unit>
<trans-unit id="40bca1e" xml:space="preserve" approved="no" translate="yes">
<source>File:</source>
</trans-unit>
<trans-unit id="a7a8df22" xml:space="preserve" approved="no" translate="yes">
<source>&gt;Originator&lt;</source>
</trans-unit>
<trans-unit id="708517ea" xml:space="preserve" approved="no" translate="yes">
<source>English:</source>
</trans-unit>
<trans-unit id="d795e193" xml:space="preserve" approved="no" translate="yes">
<source>&gt;existing&lt;</source>
</trans-unit>
<trans-unit id="c0bfb7c9" xml:space="preserve" approved="no" translate="yes">
<source>Translation:</source>
</trans-unit>
<trans-unit id="704fb514" xml:space="preserve" approved="no" translate="yes">
<source>&gt;score</source>
</trans-unit>
<trans-unit id="d80b8ff5" xml:space="preserve" approved="no" translate="yes">
<source>negative vote</source>
</trans-unit>
<trans-unit id="9f05fcb1" xml:space="preserve" approved="no" translate="yes">
<source>positive vote</source>
</trans-unit>
<trans-unit id="5b0fe134" xml:space="preserve" approved="no" translate="yes">
<source>Vote on this translation.</source>
</trans-unit>
<trans-unit id="4dca5801" xml:space="preserve" approved="no" translate="yes">
<source>If you vote positive the translation is added to your local translation list.</source>
</trans-unit>
</body>
</file>
<file original="Translator_p.html" source-language="en" datatype="html">
<body>
<trans-unit id="2eae05fc" xml:space="preserve" approved="no" translate="yes">
@ -8638,6 +8775,9 @@
<trans-unit id="7752d013" xml:space="preserve" approved="no" translate="yes">
<source>Target Language:</source>
</trans-unit>
<trans-unit id="67dd468b" xml:space="preserve" approved="no" translate="yes">
<source>activate a different language</source>
</trans-unit>
<trans-unit id="5ad17261" xml:space="preserve" approved="no" translate="yes">
<source>Source File</source>
</trans-unit>
@ -10017,6 +10157,9 @@
<trans-unit id="a66de681" xml:space="preserve" approved="no" translate="yes">
<source>&gt;Local Peer Wiki&lt;</source>
</trans-unit>
<trans-unit id="cf394e0e" xml:space="preserve" approved="no" translate="yes">
<source>UI Translations</source>
</trans-unit>
</body>
</file>

@ -170,9 +170,9 @@ Add new pattern:==Добавить новый шаблон:
The right '*', after the '/', can be replaced by a==Символом '*' (звездочка), после '/' может быть заменено
>regular expression<==>регулярным выражением<
domain.net/fullpath<==domain.net/полный путь<
>domain.net/*<==>domain.net/*<
*.domain.net/*<==*.domain.net/*<
*.sub.domain.net/*<==*.sub.domain.net/*<
#>domain.net/*<==>domain.net/*<
#*.domain.net/*<==*.domain.net/*<
#*.sub.domain.net/*<==*.sub.domain.net/*<
#sub.domain.*/*<==sub.domain.*/*<
#domain.*/*<==domain.*/*<
a complete <==полное <
@ -572,9 +572,9 @@ If checked, only non-zero values and non-empty strings are written to Solr field
Use deep-embedded local Solr&nbsp;==Использовать встроенную локальную базу Solr&nbsp;
This will write the YaCy-embedded Solr index which stored within the YaCy DATA directory.==Для записи данных будет использоваться встроенная база Solr, которая хранится в папке DATA.
The Solr native search interface is accessible at<br/>==Интерфейс поиска Solr доступен по ссылке
<a href="solr/select?q=*:*&start=0&rows=3&core=collection1">/solr/select?q=*:*&amp;start=0&amp;rows=3&amp;core=collection1</a>==<a href="solr/select?q=*:*&start=0&rows=3&core=collection1">/solr/select?q=*:*&amp;start=0&amp;rows=3&amp;core=collection1</a>
#<a href="solr/select?q=*:*&start=0&rows=3&core=collection1">/solr/select?q=*:*&amp;start=0&amp;rows=3&amp;core=collection1</a>==<a href="solr/select?q=*:*&start=0&rows=3&core=collection1">/solr/select?q=*:*&amp;start=0&amp;rows=3&amp;core=collection1</a>
for the default search index (core: collection1) and at<br/>==для поискового индекса по-умолчанию (ядро: collection1) и <br/>
<a href="solr/select?q=*:*&start=0&rows=3&core=webgraph">/solr/select?q=*:*&amp;start=0&amp;rows=3&amp;core=webgraph</a>==<a href="solr/select?q=*:*&start=0&rows=3&core=webgraph">/solr/select?q=*:*&amp;start=0&amp;rows=3&amp;core=webgraph</a>
#<a href="solr/select?q=*:*&start=0&rows=3&core=webgraph">/solr/select?q=*:*&amp;start=0&amp;rows=3&amp;core=webgraph</a>==<a href="solr/select?q=*:*&start=0&rows=3&core=webgraph">/solr/select?q=*:*&amp;start=0&amp;rows=3&amp;core=webgraph</a>
for the webgraph core.<br/>==для ядра вэб-контента.<br/>
If you switch off this index, a remote Solr must be activated.==Если вы выключите использование встроенной базы, то будет активирована удалённая база Solr.
Use remote Solr server(s)==Использовать удалённую базу Solr
@ -1820,7 +1820,7 @@ Delete local search index (embedded Solr and old Metadata)==Удалить ло
Delete remote solr index==Удалить удалённый индекс базы Solr
Delete RWI Index (DHT transmission words)==Удалить индекс RWI (передача слов в виде DHT)
Delete Citation Index (linking between URLs)==Удалить индекс цитат (перекрестные ссылки)
Delete First-Seen Date Table==Delete First-Seen Date Table
#Delete First-Seen Date Table==Delete First-Seen Date Table
Delete HTTP &amp; FTP Cache==Удалить HTTP &amp; FTP кэш
Stop Crawler and delete Crawl Queues==Остановить индексатор и удалить очередь запросов
Delete robots.txt Cache==Удалить кэш robots.txt
@ -2055,7 +2055,7 @@ This is the most generic option: select a set of documents using a solr query.==
#File: IndexImport_p.html
#---------------------------
YaCy '#[clientname]#': Index Import==YaCy '#[clientname]#': Index Import
#YaCy '#[clientname]#': Index Import==YaCy '#[clientname]#': Index Import
#Crawling Queue Import==Crawling Puffer Import
#Index DB Import==Index Datenbank Import
#The local index currently consists of (at least) #[wcount]# reverse word indexes and #[ucount]# URL references.==Der lokale Index besteht zur Zeit aus (mindestens) #[wcount]# Wörtern und #[ucount]# URLs.
@ -4064,7 +4064,7 @@ e="Search"==e="Поиск"
Search Page==Страница поиска
This search result can also be retrieved as RSS/<a href="http://www.opensearch.org" target="_blank">opensearch</a> output.==Результат поиска может быть отправлен в RSS-ленту/<a href="http://www.opensearch.org">OpenSearch</a>.
The query format is similar to==Формат запроса аналогичен
SRU==SRU
#SRU==SRU
Click the API icon to see an example call to the search rss API.==Нажмите для просмотра примера вызова API поиска RSS-ленты.
To see a list of all APIs, please visit the==Список всех API, смотрите на
API wiki page==Wiki-странице API

@ -86,9 +86,9 @@ Add new pattern:==Додати новий шаблон:
"Add URL pattern"=="Додати шаблон URL"
The right '*', after the '/', can be replaced by a <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">regex</a>.==Права "*", після "/", може бути замінена на <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">регулярний вираз</a>.
domain.net/fullpath<==domain.de/повний шлях<
>domain.net/*<==>domain.de/*<
*.domain.net/*<==*.domain.de/*<
*.sub.domain.net/*<==*.sub.domain.de/*<
#>domain.net/*<==>domain.de/*<
#*.domain.net/*<==*.domain.de/*<
#*.sub.domain.net/*<==*.sub.domain.de/*<
#sub.domain.*/*<==sub.domain.*/*<
#domain.*/*<==domain.*/*<
a complete <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">regex</a> (slow)==повний <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/regex/Pattern.html">регулярний вираз</a> (повільний)
@ -1747,7 +1747,7 @@ The assortment directory containing parts of the word index.==Каталог н
The words directory containing parts of the word index.==Каталог слів містить частини індексу слів.
The assortment file that should be imported.==Файл набору, що повинен бути імпортований.
The assortment file must have the postfix==Файл набору повинен мати закінчення
.db".==.db".
#.db".==.db".
If you would like to import an assortment file from the <tt>PLASMADBACLUSTERABKP</tt>==Якщо ви хочете імпортувати файл набору з <tt>PLASMADBACLUSTERABKP</tt>,
you have to rename it first.==ви повинні спочатку його перейменувати.
>Notes:==>Примітки:
@ -2505,7 +2505,7 @@ Crawl results will appear in the==Показ результатів знаход
Peers offering remote crawl URLs==Вузли, що пропонують URL для віддаленого сканування
If the remote crawl option is switched on, then this peer will load URLs from the following remote peers:==Якщо віддалене сканування увімкнене, то цей вузол скануватиме URL-адреси з таких віддалених вузлів:
>Name<==>Ім’я<
>Remote<br/>Crawl<==>Remote<br/>Crawl<
#>Remote<br/>Crawl<==>Remote<br/>Crawl<
>Release/<br/>SVN<==>Випуск/SVN<
>PPM<==>Сторінок За Хвилину (PPM)<
>QPH<==>Запитів За Годину (QPH)<

@ -606,11 +606,6 @@
<groupId>xerces</groupId>
<artifactId>xercesImpl</artifactId>
<version>2.11.0</version>
</dependency>
<dependency>
<groupId>com.collaborne</groupId>
<artifactId>xliff-core-1.2</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>com.adobe.xmp</groupId>

@ -133,7 +133,10 @@ public class ConcurrentScoreMap<E> extends AbstractScoreMap<E> implements ScoreM
if (obj == null) return;
// use atomic operations
this.map.putIfAbsent(obj, new AtomicLong(0));
final AtomicLong old = this.map.putIfAbsent(obj, new AtomicLong(0));
// adjust overall counter if value replaced
if (old != null) this.gcount -= old.longValue(); // must use old befor setting a new value (it's a object reference)
this.map.get(obj).set(newScore);
// increase overall counter

@ -170,7 +170,7 @@ public class Tokenizer {
wsp.inc();
} else {
// word does not yet exist, create new word entry
wordHandle = wordHandleCount++;
wordHandle = ++wordHandleCount; // let start pos with 1
wsp = new Word(wordHandle, wordInSentenceCounter, /* sentences.size() + */ 100);
wsp.flags = this.RESULT_FLAGS.clone();
this.words.put(word.toLowerCase(), wsp);

@ -252,9 +252,16 @@ public final class WordReferenceRow extends AbstractReference implements WordRef
return (0xff & this.entry.getColByte(col_hitcount));
}
/**
* First position of word in text
* @return Collection with one element
*/
@Override
public Collection<Integer> positions() {
return new ArrayList<Integer>(0);
int pos = (int) this.entry.getColLong(col_posintext);
ArrayList arr = new ArrayList<Integer>(1);
arr.add(pos);
return arr;
}
@Override

@ -60,10 +60,11 @@ public class WordReferenceVars extends AbstractReference implements WordReferenc
public final byte[] urlHash;
private String hostHash = null;
private final char type;
private int hitcount, llocal, lother, phrasesintext,
posinphrase, posofphrase,
urlcomps, urllength,
wordsintext, wordsintitle;
private int hitcount, // how often appears this word in the text
llocal, lother, phrasesintext,
posinphrase, posofphrase,
urlcomps, urllength,
wordsintext, wordsintitle;
private int virtualAge;
private final Queue<Integer> positions;
private double termFrequency;
@ -210,6 +211,10 @@ public class WordReferenceVars extends AbstractReference implements WordReferenc
return this.type;
}
/**
* How often appears this word in the text
* @return
*/
@Override
public int hitcount() {
return this.hitcount;
@ -259,7 +264,9 @@ public class WordReferenceVars extends AbstractReference implements WordReferenc
this.hitcount, // how often appears this word in the text
this.wordsintext, // total number of words
this.phrasesintext, // total number of phrases
this.positions.isEmpty() ? 1 : this.positions.iterator().next(), // position of word in all words
// TODO: positon 1 on empty positions may give high ranking scores for unknown pos (needs to be checked if 0 would be appropriate)
this.positions.isEmpty() ? -1 : this.positions.iterator().next(), // position of word in all words
this.posinphrase, // position of word in its phrase
this.posofphrase, // number of the phrase where word appears
this.lastModified, // last-modified time of the document where word appears

@ -63,9 +63,17 @@ public abstract class AbstractReference implements Reference {
private static int max(Collection<Integer> a) {
if (a == null || a.isEmpty()) return Integer.MIN_VALUE;
Iterator<Integer> i = a.iterator();
/*
expirienced concurrency issue with this short cut 2016-09-06
on i.next w/o test of hasNext before
java.util.NoSuchElementException at java.util.concurrent.LinkedBlockingQueue$Itr.next(LinkedBlockingQueue.java:828)
if (a.size() == 1) return i.next();
if (a.size() == 2) return Math.max(i.next(), i.next());
int r = i.next();
*/
int r = Integer.MIN_VALUE;
int s;
while (i.hasNext()) {
s = i.next();
@ -77,9 +85,12 @@ public abstract class AbstractReference implements Reference {
private static int min(Collection<Integer> a) {
if (a == null || a.isEmpty()) return Integer.MAX_VALUE;
Iterator<Integer> i = a.iterator();
/* concurrency issue (see max())
if (a.size() == 1) return i.next();
if (a.size() == 2) return Math.min(i.next(), i.next());
int r = i.next();
*/
int r = Integer.MAX_VALUE;
int s;
while (i.hasNext()) {
s = i.next();
@ -103,10 +114,11 @@ public abstract class AbstractReference implements Reference {
if (positions().size() < 2) return 0;
int d = 0;
Iterator<Integer> i = positions().iterator();
int s0 = i.next(), s1;
// int s0 = i.next(), s1; // concurrency issue see max()
int s0 = -1, s1;
while (i.hasNext()) {
s1 = i.next();
d += Math.abs(s0 - s1);
if (s0 > 0) d += Math.abs(s0 - s1);
s0 = s1;
}
return d / (positions().size() - 1);

@ -206,6 +206,18 @@ public class NewsPool {
*/
private static final String CATEGORY_BLOG_DEL = "blog_del";
/* ------------------------------------------------------------------------
* TRANSLATION related CATEGORIES
* ------------------------------------------------------------------------ */
/**
* a translation was added
*/
public static final String CATEGORY_TRANSLATION_ADD = "transadd";
/**
* a vote on a translation
*/
public static final String CATEGORY_TRANSLATION_VOTE_ADD = "transavt";
/* ========================================================================
* ARRAY of valid CATEGORIES
* ======================================================================== */
@ -250,7 +262,11 @@ public class NewsPool {
// BLOG related CATEGORIES
CATEGORY_BLOG_ADD,
CATEGORY_BLOG_DEL
CATEGORY_BLOG_DEL,
// TRANSLATION related CATEGORIES
CATEGORY_TRANSLATION_ADD,
CATEGORY_TRANSLATION_VOTE_ADD
};
private static final Set<String> categories = new HashSet<String>();
static {
@ -309,6 +325,8 @@ public class NewsPool {
if (this.newsDB.get(record.id()) == null) {
this.incomingNews.push(record); // we want to see our own news..
this.outgoingNews.push(record); // .. and put it on the publishing list
} else {
ConcurrentLog.info("NewsPool", "publishing of news aborted, news with same id (time + originator) exists id=" + record.id());
}
} catch (final Exception e) {
ConcurrentLog.logException(e);
@ -398,35 +416,56 @@ public class NewsPool {
return pc;
}
/**
* Check max keep duration depending on news category and return true if duration
* is exceeded
*
* @param seedDB
* @param record
* @return true if news should be removed
*/
private static boolean automaticProcessP(final SeedDB seedDB, final NewsDB.Record record) {
if (record == null) return false;
if (record.category() == null) return true;
final long created = record.created().getTime();
if ((System.currentTimeMillis() - created) > (6L * MILLISECONDS_PER_HOUR)) {
// remove everything after 1 day
if (record == null) {
return false;
}
if (record.category() == null) {
return true;
}
if ((record.category().equals(CATEGORY_WIKI_UPDATE)) &&
((System.currentTimeMillis() - created) > (3L * MILLISECONDS_PER_DAY))) {
return true;
}
if ((record.category().equals(CATEGORY_BLOG_ADD)) &&
((System.currentTimeMillis() - created) > (3L * MILLISECONDS_PER_DAY))) {
return true;
}
if ((record.category().equals(CATEGORY_PROFILE_UPDATE)) &&
((System.currentTimeMillis() - created) > (3L * MILLISECONDS_PER_DAY))) {
return true;
}
if ((record.category().equals(CATEGORY_CRAWL_START)) &&
((System.currentTimeMillis() - created) > (3L * MILLISECONDS_PER_DAY))) {
final Seed seed = seedDB.get(record.originator());
if (seed == null) return true;
try {
return (Integer.parseInt(seed.get(Seed.ISPEED, "-")) < 10);
} catch (final NumberFormatException ee) {
return true;
}
final long created = record.created().getTime();
final long duration = System.currentTimeMillis() - created;
String cat = record.category();
switch (cat) {
case CATEGORY_WIKI_UPDATE:
case CATEGORY_BLOG_ADD:
case CATEGORY_PROFILE_UPDATE:
if (duration > (3L * MILLISECONDS_PER_DAY)) {
return true;
}
break;
case CATEGORY_CRAWL_START:
if (duration > (3L * MILLISECONDS_PER_DAY)) {
final Seed seed = seedDB.get(record.originator());
if (seed == null) return true; // TODO: shall we keep for 3 days without sender ?
try {
return (Integer.parseInt(seed.get(Seed.ISPEED, "-")) < 10); // TODO: should we keep longer as 3 days if peer is still/currently crawling (after 3 days) ?
} catch (final NumberFormatException ee) {
return true;
}
}
break;
case CATEGORY_TRANSLATION_ADD:
case CATEGORY_TRANSLATION_VOTE_ADD:
if (duration > (7L * MILLISECONDS_PER_DAY)) {
return true;
}
break;
default:
if (duration > MILLISECONDS_PER_DAY) {
// remove everything else after 1 day
return true;
}
}
return false;
}

@ -30,7 +30,6 @@ import net.yacy.cora.document.encoding.ASCII;
import net.yacy.cora.document.feed.RSSMessage;
import net.yacy.cora.storage.ConcurrentARC;
import net.yacy.kelondro.util.MapTools;
import net.yacy.peers.operation.yacyVersion;
public class PeerActions {
@ -261,7 +260,7 @@ public class PeerActions {
final String cre1 = MapTools.string2map(decodedString, ",").get("cre");
final String cre2 = MapTools.string2map(record.toString(), ",").get("cre");
if ((cre1 == null) || (cre2 == null) || (!(cre1.equals(cre2)))) {
System.out.println("### ERROR - cre are not equal: cre1=" + cre1 + ", cre2=" + cre2);
Network.log.warn("processPeerArrival: ### ERROR - message creation date verification not equal: cre1=" + cre1 + ", cre2=" + cre2);
return;
}
try {

@ -1329,10 +1329,32 @@ public final class SearchEvent {
public long getSnippetComputationTime() {
return this.snippetComputationAllTime;
}
public ScoreMap<String> getTopicNavigator(final int count ) {
/**
* Get topics in a ScoreMap if config allows topic navigator
* (the topics are filtered by badwords, stopwords and words included in the query)
*
* @param count max number of topics returned
* @return ScoreMap with max number of topics or null if
*/
public ScoreMap<String> getTopicNavigator(final int count) {
if (this.topicNavigatorCount > 0 && count >= 0) { //topicNavigatorCount set during init, 0=no nav
return this.getTopics(count != 0 ? count : this.topicNavigatorCount, 500);
if (!this.ref.sizeSmaller(2)) {
ScoreMap<String> result;
int ic = count != 0 ? count : this.topicNavigatorCount;
if (this.ref.size() <= ic) { // size matches return map directly
result = this.getTopics(/*ic, 500*/);
} else { // collect top most count topics
result = new ConcurrentScoreMap<String>();
Iterator<String> it = this.getTopics(/*ic, 500*/).keys(false);
while (ic-- > 0 && it.hasNext()) {
String word = it.next();
result.set(word, this.ref.get(word));
}
}
return result;
}
}
return null;
}
@ -1428,7 +1450,11 @@ public final class SearchEvent {
*/
public void addResult(URIMetadataNode resultEntry, final float score) {
if (resultEntry == null) return;
final long ranking = ((long) (score * 128.f)) + postRanking(resultEntry, new ConcurrentScoreMap<String>() /*this.snippetProcess.rankingProcess.getTopicNavigator(10)*/);
final long ranking = ((long) (score * 128.f)) + postRanking(resultEntry, this.ref /*this.getTopicNavigator(MAX_TOPWORDS)*/);
// TODO: above was originally using (see below), but getTopicNavigator returns this.ref and possibliy alters this.ref on first call (this.ref.size < 2 -> this.ref.clear)
// TODO: verify and straighten the use of addTopic, getTopic and getTopicNavigator and related score calculation
// final long ranking = ((long) (score * 128.f)) + postRanking(resultEntry, this.getTopicNavigator(MAX_TOPWORDS));
resultEntry.setScore(ranking); // update the score of resultEntry for access by search interface / api
this.resultList.put(new ReverseElement<URIMetadataNode>(resultEntry, ranking)); // remove smallest in case of overflow
if (pollImmediately) this.resultList.poll(); // prevent re-ranking in case there is only a single index source which has already ranked entries.
@ -1439,10 +1465,19 @@ public final class SearchEvent {
long r = 0;
// for media search: prefer pages with many links
r += rentry.limage() << this.query.ranking.coeff_cathasimage;
r += rentry.laudio() << this.query.ranking.coeff_cathasaudio;
r += rentry.lvideo() << this.query.ranking.coeff_cathasvideo;
r += rentry.lapp() << this.query.ranking.coeff_cathasapp;
switch (this.query.contentdom) {
case IMAGE:
r += rentry.limage() << this.query.ranking.coeff_cathasimage;
break;
case AUDIO:
r += rentry.laudio() << this.query.ranking.coeff_cathasaudio;
break;
case VIDEO:
r += rentry.lvideo() << this.query.ranking.coeff_cathasvideo;
break;
case APP:
r += rentry.lapp() << this.query.ranking.coeff_cathasapp;
}
// apply citation count
//System.out.println("POSTRANKING CITATION: references = " + rentry.referencesCount() + ", inbound = " + rentry.llocal() + ", outbound = " + rentry.lother());
@ -1458,24 +1493,27 @@ public final class SearchEvent {
final String urlstring = rentry.url().toNormalform(true);
final String[] urlcomps = MultiProtocolURL.urlComps(urlstring);
final String[] descrcomps = MultiProtocolURL.splitpattern.split(rentry.title().toLowerCase());
for (final String urlcomp : urlcomps) {
// apply query-in-result matching
final QueryGoal.NormalizedWords urlcompmap = new QueryGoal.NormalizedWords(urlcomps);
final QueryGoal.NormalizedWords descrcompmap = new QueryGoal.NormalizedWords(descrcomps);
// the token map is used (instead of urlcomps/descrcomps) to determine appearance in url/title and eliminate double occurances
// (example Title="News News News News News News - today is party -- News News News News News News" to add one score instead of 12 * score !)
for (final String urlcomp : urlcompmap) {
int tc = topwords.get(urlcomp);
if (tc > 0) r += Math.max(1, tc) << this.query.ranking.coeff_urlcompintoplist;
}
for (final String descrcomp : descrcomps) {
for (final String descrcomp : descrcompmap) {
int tc = topwords.get(descrcomp);
if (tc > 0) r += Math.max(1, tc) << this.query.ranking.coeff_descrcompintoplist;
}
// apply query-in-result matching
final QueryGoal.NormalizedWords urlcomph = new QueryGoal.NormalizedWords(urlcomps);
final QueryGoal.NormalizedWords descrcomph = new QueryGoal.NormalizedWords(descrcomps);
final Iterator<String> shi = this.query.getQueryGoal().getIncludeWords();
String queryword;
while (shi.hasNext()) {
queryword = shi.next();
if (urlcomph.contains(queryword)) r += 256 << this.query.ranking.coeff_appurl;
if (descrcomph.contains(queryword)) r += 256 << this.query.ranking.coeff_app_dc_title;
if (urlcompmap.contains(queryword)) r += 256 << this.query.ranking.coeff_appurl;
if (descrcompmap.contains(queryword)) r += 256 << this.query.ranking.coeff_app_dc_title;
}
return r;
}
@ -1818,14 +1856,23 @@ public final class SearchEvent {
// this is only available if execQuery() was called before
return this.localSearchInclusion;
}
public ScoreMap<String> getTopics(final int maxcount, final long maxtime) {
// create a list of words that had been computed by statistics over all
// words that appeared in the url or the description of all urls
/**
* Return the list of words that had been computed by statistics over all
* words that appeared in the url or the description of all urls
*
* @return ScoreMap
*/
public ScoreMap<String> getTopics(/* final int maxcount, final long maxtime */) {
/* ---------------------------------- start of rem (2016-09-03)
// TODO: result map is not used currently, verify if it should and use or delete this code block
// TODO: as it is not used now - in favour of performance this code block is rem'ed (2016-09-03)
final ScoreMap<String> result = new ConcurrentScoreMap<String>();
if ( this.ref.sizeSmaller(2) ) {
this.ref.clear(); // navigators with one entry are not useful
}
final Map<String, Float> counts = new HashMap<String, Float>();
final Iterator<String> i = this.ref.keys(false);
String word;
@ -1851,11 +1898,17 @@ public final class SearchEvent {
result.set(ce.getKey(), (int) (((double) maxcount) * (ce.getValue() - min) / (max - min)));
}
}
/* ------------------------------------ end of rem (2016-09-03) */
return this.ref;
}
private final static Pattern lettermatch = Pattern.compile("[a-z]+");
/**
* Collects topics in a ScoreMap for words not included in the query words.
* Words are also filtered by badword blacklist and stopword list.
* @param words
*/
public void addTopic(final String[] words) {
String word;
for ( final String w : words ) {
@ -1872,6 +1925,10 @@ public final class SearchEvent {
}
}
/**
* Ad title words to this searchEvent's topic score map
* @param resultEntry
*/
protected void addTopics(final URIMetadataNode resultEntry) {
// take out relevant information for reference computation
if ((resultEntry.url() == null) || (resultEntry.title() == null)) return;

@ -228,13 +228,13 @@ public class ReferenceOrder {
assert this.ranking != null;
final long tf = ((this.max.termFrequency() == this.min.termFrequency()) ? 0 : (((int)(((t.termFrequency()-this.min.termFrequency())*256.0)/(this.max.termFrequency() - this.min.termFrequency())))) << this.ranking.coeff_termfrequency);
//System.out.println("tf(" + t.urlHash + ") = " + Math.floor(1000 * t.termFrequency()) + ", min = " + Math.floor(1000 * min.termFrequency()) + ", max = " + Math.floor(1000 * max.termFrequency()) + ", tf-normed = " + tf);
final int maxmaxpos = this.max.maxposition();
final int maxmaxpos = this.max.maxposition(); // returns Integer.MIN_VALUE if positions empty
final int minminpos = this.min.minposition();
final long r =
((256 - DigestURL.domLengthNormalized(t.urlhash())) << this.ranking.coeff_domlength)
+ ((this.max.urlcomps() == this.min.urlcomps() ) ? 0 : (256 - (((t.urlcomps() - this.min.urlcomps() ) << 8) / (this.max.urlcomps() - this.min.urlcomps()) )) << this.ranking.coeff_urlcomps)
+ ((this.max.urllength() == this.min.urllength() ) ? 0 : (256 - (((t.urllength() - this.min.urllength() ) << 8) / (this.max.urllength() - this.min.urllength()) )) << this.ranking.coeff_urllength)
+ ((maxmaxpos == minminpos) ? 0 : (256 - (((t.minposition() - minminpos) << 8) / (maxmaxpos - minminpos))) << this.ranking.coeff_posintext)
+ ((maxmaxpos == minminpos || maxmaxpos < 0) ? 0 : (256 - (((t.minposition() - minminpos) << 8) / (maxmaxpos - minminpos))) << this.ranking.coeff_posintext)
+ ((this.max.posofphrase() == this.min.posofphrase()) ? 0 : (256 - (((t.posofphrase() - this.min.posofphrase() ) << 8) / (this.max.posofphrase() - this.min.posofphrase()) )) << this.ranking.coeff_posofphrase)
+ ((this.max.posinphrase() == this.min.posinphrase()) ? 0 : (256 - (((t.posinphrase() - this.min.posinphrase() ) << 8) / (this.max.posinphrase() - this.min.posinphrase()) )) << this.ranking.coeff_posinphrase)
+ ((this.max.distance() == this.min.distance() ) ? 0 : (256 - (((t.distance() - this.min.distance() ) << 8) / (this.max.distance() - this.min.distance()) )) << this.ranking.coeff_worddistance)

@ -64,7 +64,7 @@ public final class serverClassLoader extends ClassLoader {
@Override
protected Class<?> findClass(String classname) throws ClassNotFoundException {
// construct path to htroot for a servletname
File cpath = new File (Switchboard.getSwitchboard().getDataPath(SwitchboardConstants.HTROOT_PATH, SwitchboardConstants.HTROOT_PATH_DEFAULT),classname+".class");
File cpath = new File (Switchboard.getSwitchboard().getAppPath(SwitchboardConstants.HTROOT_PATH, SwitchboardConstants.HTROOT_PATH_DEFAULT),classname+".class");
return loadClass(cpath);
}

@ -1,4 +1,4 @@
// CreateTranslationMasters.java
// TranslationManager.java
// -------------------------------------
// part of YACY
// (C) by Michael Peter Christen; mc@yacy.net
@ -40,6 +40,8 @@ import java.util.Map;
import java.util.TreeMap;
import net.yacy.cora.util.ConcurrentLog;
import net.yacy.data.Translator;
import net.yacy.search.Switchboard;
import net.yacy.search.SwitchboardConstants;
/**
* Utility to create a translation master file from all existing translation
@ -47,7 +49,35 @@ import net.yacy.data.Translator;
* Also can join existing translation with master (currently ristrictive,
* means only translation text exist in master are included in resultin Map
*/
public class CreateTranslationMasters extends TranslatorXliff {
public class TranslationManager extends TranslatorXliff {
protected Map<String, Map<String, String>> mainTransLists; // current translation entries for one language
protected String loadedLng; // language loaded in mainTransLists (2-letter code)
public TranslationManager() {
super();
}
public TranslationManager(final File langfile) {
mainTransLists = loadTranslationsLists(langfile);
int pos = langfile.getName().indexOf('.');
if (pos >= 0) {
loadedLng = langfile.getName().substring(0, pos);
}
}
/**
* Add a translation text to the current map map
*
* @param relFileName relative filename the translation belongs to
* @param sourceLngTxt the english source text
* @param targetLngTxt the translated text
* @return true = if map was modified, otherwise false
*/
public boolean addTranslation(final String relFileName, final String sourceLngTxt, final String targetLngTxt) {
assert mainTransLists != null;
return addTranslation (mainTransLists, relFileName, sourceLngTxt, targetLngTxt);
}
/**
* Helper to add a translation text to the map
@ -79,6 +109,58 @@ public class CreateTranslationMasters extends TranslatorXliff {
return modified;
}
/**
* Get the translation list for a ui/html file
* @param filename relative path to htroot
* @return translation map or null
*/
public Map<String, String> getTranslationForFile(String filename) {
return mainTransLists.get(filename);
}
/**
* Get a translation target text
* @param filename of the translation
* @param source english source text
* @return translated text or null
*/
public String getTranslation (String filename, String source) {
Map<String, String> tmp = mainTransLists.get(filename);
if (tmp != null)
return tmp.get(source);
else
return null;
}
/**
* Translates one file. The relFilepath is the file name as given in the
* translation source lists. The source (english) file is expected under
* htroot path. The destination file is under DATA/LOCALE and calculated
* using the language of loaded data.
*
* @param relFilepath file name releative to htroot
* @return true on success
*/
public boolean translateFile(String relFilepath) {
assert loadedLng != null;
assert mainTransLists != null;
boolean result = false;
if (mainTransLists.containsKey(relFilepath)) {
Switchboard sb = Switchboard.getSwitchboard();
if (sb != null) {
final String htRootPath = sb.getConfig(SwitchboardConstants.HTROOT_PATH, SwitchboardConstants.HTROOT_PATH_DEFAULT);
final File sourceDir = new File(sb.getAppPath(), htRootPath);
final File destDir = new File(sb.getDataPath("locale.translated_html", "DATA/LOCALE/htroot"), loadedLng);
// get absolute file by adding relative filename
final File sourceFile = new File(sourceDir, relFilepath);
final File destFile = new File(destDir, relFilepath);
result = translateFile(sourceFile, destFile, mainTransLists.get(relFilepath)); // do the translation
}
}
return result;
}
/**
* Create a master translation list by reading all translation files
* If a masterOutputFile exists, content is preserved (loaded first)
@ -87,11 +169,10 @@ public class CreateTranslationMasters extends TranslatorXliff {
* @throws IOException
*/
public void createMasterTranslationLists(File masterOutputFile) throws IOException {
Map<String, Map<String, String>> xliffTrans;
if (masterOutputFile.exists()) // if file exists, conserve existing master content (may be updated by external tool)
xliffTrans = loadTranslationsListsFromXliff(masterOutputFile);
mainTransLists = loadTranslationsListsFromXliff(masterOutputFile);
else
xliffTrans = new TreeMap<String, Map<String, String>>();
mainTransLists = new TreeMap<String, Map<String, String>>();
List<String> lngFiles = Translator.langFiles(new File("locales"));
for (String filename : lngFiles) {
@ -130,7 +211,7 @@ public class CreateTranslationMasters extends TranslatorXliff {
// it is possible that intentionally empty translation is given
// in this case xliff target is missing (=null)
if (origVal != null && !origVal.isEmpty()) { // if translation exists
addTranslation(xliffTrans, transfilename, sourcetxt, null); // add to master, set target text null
addTranslation(transfilename, sourcetxt, null); // add to master, set target text null
}
}
}
@ -140,11 +221,14 @@ public class CreateTranslationMasters extends TranslatorXliff {
}
}
// save as xliff file w/o language code
saveAsXliff(null, masterOutputFile, xliffTrans);
saveAsXliff(null, masterOutputFile, mainTransLists);
}
/**
* Joins translation master (xliff) and existing translation (lng)
* Joins translation master (xliff) and existing translation (lng).
* Only texts existing in master are included from the lngfile,
* the resulting map includes all keys from master with the matching translation
* from lngfile.
*
* @param xlifmaster master (with en text to be translated)
* @param lngfile existing translation
@ -154,7 +238,7 @@ public class CreateTranslationMasters extends TranslatorXliff {
public Map<String, Map<String, String>> joinMasterTranslationLists(File xlifmaster, File lngfile) throws IOException {
final String filename = lngfile.getName();
Map<String, Map<String, String>> xliffTrans = loadTranslationsListsFromXliff(xlifmaster);
mainTransLists = loadTranslationsListsFromXliff(xlifmaster);
// load translation list
ConcurrentLog.info("TRANSLATOR", "join into master translation file " + filename);
Map<String, Map<String, String>> origTrans = loadTranslationsLists(lngfile);
@ -162,46 +246,50 @@ public class CreateTranslationMasters extends TranslatorXliff {
for (String transfilename : origTrans.keySet()) { // get translation filename
// compare translation list
Map<String, String> origList = origTrans.get(transfilename);
Map<String, String> masterList = xliffTrans.get(transfilename);
Map<String, String> masterList = mainTransLists.get(transfilename);
for (String sourcetxt : origList.keySet()) {
if ((masterList != null) && (masterList.isEmpty() || masterList.containsKey(sourcetxt))) { // only if included in master (as all languages are in there but checked for occuance
String origVal = origList.get(sourcetxt);
// it is possible that intentionally empty translation is given
// in this case xliff target is missing (=null)
if (origVal != null && !origVal.isEmpty()) {
addTranslation(xliffTrans, transfilename, sourcetxt, origVal);
addTranslation(transfilename, sourcetxt, origVal);
}
}
}
}
return xliffTrans;
return mainTransLists;
}
/**
* for testing to create on master and joined translation results for all lang's
*
* @param args
* Stores the loaded translations to a .lng file
* @param lng
* @param f
* @return
*/
public static void main(String args[]) {
File outputdirectory = new File ("test/DATA");
CreateTranslationMasters ctm = new CreateTranslationMasters();
try {
if (!outputdirectory.exists()) outputdirectory.mkdir();
File xlfmaster = new File(outputdirectory, "master.lng.xlf");
ctm.createMasterTranslationLists(xlfmaster); // write the language neutral translation master as xliff
List<String> lngFiles = Translator.langFiles(new File("locales"));
for (String filename : lngFiles) {
Map<String, Map<String, String>> lngmaster = ctm.joinMasterTranslationLists(xlfmaster, new File("locales", filename)); // create individual language translation files from master
File xlftmp = new File(outputdirectory, filename + ".xlf");
System.out.println("output new master translation file " + xlftmp.toString() + " and " + filename);
ctm.saveAsXliff(filename.substring(0, 2), xlftmp, lngmaster);
ctm.saveAsLngFile(filename.substring(0, 2), new File(outputdirectory, filename), lngmaster);
}
} catch (IOException ex) {
ConcurrentLog.logException(ex);
public boolean saveXliff(final String lng, File f) {
return this.saveAsXliff(lng, f, mainTransLists);
}
/**
* Stores the loaded translations to a .xlf file
* @param lng
* @param f
* @return
*/
public boolean saveLng(final String lng, File f) {
return this.saveAsLngFile(lng, f, mainTransLists);
}
/**
* Total number of loaded translation entries
* @return
*/
public int size() {
int i = 0;
for (Map<String, String> trans : mainTransLists.values()) {
i += trans.size();
}
ConcurrentLog.shutdown();
return i;
}
}

@ -29,27 +29,22 @@ package net.yacy.utils.translation;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.stream.events.XMLEvent;
import net.yacy.cora.util.ConcurrentLog;
import net.yacy.data.Translator;
import net.yacy.search.Switchboard;
import org.oasis.xliff.core_12.Body;
import org.oasis.xliff.core_12.Target;
import org.oasis.xliff.core_12.TransUnit;
import org.oasis.xliff.core_12.Xliff;
/**
* Wordlist based translator
@ -88,55 +83,70 @@ public class TranslatorXliff extends Translator {
* <file>.....
* </xliff>
*/
Xliff xliffTranslation;
try (FileInputStream fis = new FileInputStream(xliffFile)){ // try-with-resource to close inputstream
JAXBContext ctx = JAXBContext.newInstance(org.oasis.xliff.core_12.Xliff.class);
Unmarshaller un = ctx.createUnmarshaller();
Object obj = un.unmarshal(fis);
if (obj instanceof org.oasis.xliff.core_12.Xliff) {
xliffTranslation = (org.oasis.xliff.core_12.Xliff) obj;
} else {
return null;
}
List<Object> xlfFileList = xliffTranslation.getAnyAndFile();
for (Object xlfobj : xlfFileList) {
org.oasis.xliff.core_12.File xlfFileNode = (org.oasis.xliff.core_12.File) xlfobj;
Map<String, String> translationList; //current Translation Table (maintaining input order)
String forFile = xlfFileNode.getOriginal();
if (lngLists.containsKey(forFile)) {
translationList = lngLists.get(forFile);
} else {
translationList = new LinkedHashMap<String, String>(); //current Translation Table (maintaining input order)
lngLists.put(forFile, translationList);
}
try (FileInputStream fis = new FileInputStream(xliffFile)) { // try-with-resource to close inputstream
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLStreamReader xmlreader = factory.createXMLStreamReader(fis);
Map<String, String> translationList = null; //current Translation Table (maintaining input order)
String source = null;
String target = null;
String state = null;
while (xmlreader.hasNext()) {
int eventtype = xmlreader.next();
if (eventtype == XMLEvent.START_ELEMENT) {
String ename = xmlreader.getLocalName();
Body xlfBody = xlfFileNode.getBody();
List<Object> xlfTransunitList = xlfBody.getGroupOrTransUnitOrBinUnit();
for (Object xlfTransunit : xlfTransunitList) {
if (xlfTransunit instanceof TransUnit) {
String source = ((TransUnit) xlfTransunit).getSource().getContent().get(0).toString();
Target target = ((TransUnit) xlfTransunit).getTarget();
if (target != null) {
if ("translated".equals(target.getState())) {
List<Object> targetContentList = target.getContent();
String targetContent = targetContentList.get(0).toString();
translationList.put(source, targetContent);
// setup for 'file' section (get or add translationlist for this file)
if (ename.equalsIgnoreCase("file")) {
String forFile = xmlreader.getAttributeValue(null, "original");
if (lngLists.containsKey(forFile)) {
translationList = lngLists.get(forFile);
} else {
translationList = new LinkedHashMap<String, String>(); //current Translation Table (maintaining input order)
lngLists.put(forFile, translationList);
}
source = null;
target = null;
} else if (ename.equalsIgnoreCase("trans-unit")) { // prepare for trans-unit
source = null;
target = null;
} else if (ename.equalsIgnoreCase("source")) { // get source text
source = xmlreader.getElementText();
} else if (ename.equalsIgnoreCase("target")) { // get target text
state = xmlreader.getAttributeValue(null, "state");
target = xmlreader.getElementText(); // TODO: in full blown xliff, target may contain sub-xml elements (but we use only text)
}
} else if (eventtype == XMLEvent.END_ELEMENT) {
String ename = xmlreader.getLocalName();
// store source/target on finish of trans-unit
if (ename.equalsIgnoreCase("trans-unit") && translationList != null) {
if (source != null) {
if (target != null) {
if ("translated".equals(state)) {
translationList.put(source, target);
} else {
translationList.put(source, null);
}
} else {
translationList.put(source, null);
}
} else {
translationList.put(source, null);
source = null;
}
target = null;
}
// on file end-tag make sure nothing is added (on error in xml)
if (ename.equalsIgnoreCase("file")) {
translationList = null;
}
}
}
} catch (JAXBException je) {
ConcurrentLog.warn("TRANSLATOR", je.getMessage());
} catch (FileNotFoundException ex) {
ConcurrentLog.warn("TRANSLATOR", "File not found: " + xliffFile.getAbsolutePath());
} catch (IOException ex) {
ConcurrentLog.warn("TRANSLATOR", ex.getMessage());
xmlreader.close();
} catch (IOException | XMLStreamException ex) {
ConcurrentLog.warn("TRANSLATOR", "error reading " + xliffFile.getAbsolutePath() + " -> " + ex.getMessage());
}
return lngLists;
}

@ -713,13 +713,17 @@ public final class yacy {
//System.out.print("args=["); for (int i = 0; i < args.length; i++) System.out.print(args[i] + ", "); System.out.println("]");
if ((args.length >= 1) && (args[0].toLowerCase().equals("-startup") || args[0].equals("-start"))) {
// normal start-up of yacy
if (args.length > 1) dataRoot = new File(System.getProperty("user.home").replace('\\', '/'), args[1]);
preReadSavedConfigandInit(dataRoot);
if (args.length > 1) {
dataRoot = new File(System.getProperty("user.home").replace('\\', '/'), args[1]);
}
preReadSavedConfigandInit(dataRoot);
startup(dataRoot, applicationRoot, startupMemFree, startupMemTotal, false);
} else if (args.length >= 1 && args[0].toLowerCase().equals("-gui")) {
// start-up of yacy with gui
if (args.length > 1) dataRoot = new File(System.getProperty("user.home").replace('\\', '/'), args[1]);
preReadSavedConfigandInit(dataRoot);
if (args.length > 1) {
dataRoot = new File(System.getProperty("user.home").replace('\\', '/'), args[1]);
}
preReadSavedConfigandInit(dataRoot);
startup(dataRoot, applicationRoot, startupMemFree, startupMemTotal, true);
} else if ((args.length >= 1) && ((args[0].toLowerCase().equals("-shutdown")) || (args[0].equals("-stop")))) {
// normal shutdown of yacy
@ -732,7 +736,7 @@ public final class yacy {
} else if ((args.length >= 1) && (args[0].toLowerCase().equals("-version"))) {
// show yacy version
System.out.println(copyright);
} else if ((args.length > 1) && (args[0].toLowerCase().equals("-config"))) {
} else if ((args.length > 1) && (args[0].toLowerCase().equals("-config"))) {
// set config parameter. Special handling of adminAccount=user:pwd (generates md5 encoded password)
// on Windows parameter should be enclosed in doublequotes to accept = sign (e.g. -config "port=8090" "port.ssl=8043")
File f = new File (dataRoot,"DATA/SETTINGS/");
@ -778,9 +782,11 @@ public final class yacy {
}
System.out.println();
}
} else {
if (args.length == 1) applicationRoot= new File(args[0]);
preReadSavedConfigandInit(dataRoot);
} else {
if (args.length == 1) {
applicationRoot= new File(args[0]);
}
preReadSavedConfigandInit(dataRoot);
startup(dataRoot, applicationRoot, startupMemFree, startupMemTotal, false);
}
} finally {

@ -40,6 +40,7 @@ Options
-l, --logging save the output of YaCy to yacy.log
-d, --debug show the output of YaCy on the console
-p, --print-out only print the command, which would be executed to start YaCy
-s, --startup [data-path] start YaCy using the specified data folder path, relative to the current user home
-g, --gui start a gui for YaCy
USAGE
}
@ -47,16 +48,16 @@ USAGE
#startup YaCy
cd "`dirname $0`"
if [ $OS = "OpenBSD" ]
if [ $OS = "OpenBSD" ] || [ $OS = "Darwin" ]
then
if [ $(echo $@ | grep -o "\-\-" | wc -l) -ne 0 ]
then
echo "WARNING: Unfortunately this script does not support long options in $OS."
fi
options="`getopt hdlptg: $*`"
options="`getopt hdlptsg: $*`"
else
options="`getopt -n YaCy -o h,d,l,p,t,g -l help,debug,logging,print-out,tail-log,gui -- $@`"
options="`getopt -n YaCy -o h,d,l,p,t,s,g -l help,debug,logging,print-out,tail-log,startup,gui -- $@`"
fi
if [ $? -ne 0 ];then
@ -71,6 +72,7 @@ LOGGING=0
DEBUG=0
PRINTONLY=0
TAILLOG=0
STARTUP=0
GUI=0
for option in $options;do
if [ $isparameter -ne 1 ];then #option
@ -101,17 +103,25 @@ for option in $options;do
-t|--tail-log)
TAILLOG=1
;;
-s|-startup)
STARTUP=1
isparameter=1
;;
-g|--gui)
GUI=1
isparameter=1
;;
esac #case option
else #parameter
if [ x$option = "--" ];then #option / parameter separator
if [ $option = "--" ];then #option / parameter separator
isparameter=1;
continue
else
parameter="$parameter $option"
if [ $parameter ];then
parameter="$parameter $option"
else
parameter="$option"
fi
fi
fi #parameter or option?
done
@ -189,8 +199,11 @@ for N in lib/*.jar; do CLASSPATH="$CLASSPATH$N:"; done
CLASSPATH=".:$CLASSPATH"
cmdline="$JAVA $JAVA_ARGS -classpath $CLASSPATH net.yacy.yacy";
if [ $GUI -eq 1 ] #gui
if [ $STARTUP -eq 1 ] #startup
then
cmdline="$cmdline -startup $parameter"
elif [ $GUI -eq 1 ];then #gui
cmdline="$cmdline -gui $parameter"
fi
if [ $DEBUG -eq 1 ] #debug

@ -0,0 +1,34 @@
package net.yacy.cora.sorting;
import java.util.Iterator;
import static org.junit.Assert.assertEquals;
import org.junit.Test;
public class ConcurrentScoreMapTest {
/**
* Test of totalCount method, of class ConcurrentScoreMap.
*/
@Test
public void testTotalCount() {
final ConcurrentScoreMap<String> csm = new ConcurrentScoreMap<String>();
csm.set("first", 10);
csm.set("second", 5);
csm.set("third", 13);
csm.set("first", 100);
final Iterator<String> it = csm.keys(true);
long sum = 0;
while (it.hasNext()) {
String x = it.next();
long val = csm.get(x);
sum += val;
}
assertEquals(sum, csm.totalCount());
}
}

@ -0,0 +1,39 @@
package net.yacy.document;
import java.net.MalformedURLException;
import java.util.Map;
import net.yacy.cora.document.WordCache;
import net.yacy.kelondro.data.word.Word;
import org.junit.Test;
import static org.junit.Assert.*;
public class TokenizerTest {
/**
* Test of words method, of class Tokenizer.
*/
@Test
public void testWords() throws MalformedURLException {
// pos = 1 2 3 4 5 6 7 8 9 10 // 1-letter words don't count
String text = "One word is not a sentence because words are just words.";
WordCache meaningLib = new WordCache(null);
boolean doAutotagging = false;
VocabularyScraper scraper = null;
Tokenizer t = new Tokenizer(null, text, meaningLib, doAutotagging, scraper);
Map<String, Word> words = t.words;
// test extracted word information (position)
Word w = words.get("word");
assertEquals("position of 'word' ", 2, w.posInText);
assertEquals("occurence of 'word' ", 1, w.occurrences());
w = words.get("words");
assertEquals("position of 'words' ", 7, w.posInText);
assertEquals("occurence of 'words' ", 2, w.occurrences());
}
}
Loading…
Cancel
Save