create crawler.properties when executing job

This commit is contained in:
Shinsuke Sugaya 2016-01-02 23:59:49 +09:00
parent e862abb5e1
commit 3dc36f9de5
7 changed files with 284 additions and 155 deletions

View file

@ -139,14 +139,14 @@ public class AdminDesignAction extends FessAdminAction implements Serializable {
String baseDir = null;
// normalize filename
if (checkFileType(fileName, systemHelper.getSupportedUploadedMediaExtentions())
&& checkFileType(uploadedFileName, systemHelper.getSupportedUploadedMediaExtentions())) {
if (checkFileType(fileName, fessConfig.getSupportedUploadedMediaExtentionsAsArray())
&& checkFileType(uploadedFileName, fessConfig.getSupportedUploadedMediaExtentionsAsArray())) {
baseDir = "/images/";
} else if (checkFileType(fileName, systemHelper.getSupportedUploadedCssExtentions())
&& checkFileType(uploadedFileName, systemHelper.getSupportedUploadedCssExtentions())) {
} else if (checkFileType(fileName, fessConfig.getSupportedUploadedCssExtentionsAsArray())
&& checkFileType(uploadedFileName, fessConfig.getSupportedUploadedCssExtentionsAsArray())) {
baseDir = "/css/";
} else if (checkFileType(fileName, systemHelper.getSupportedUploadedJSExtentions())
&& checkFileType(uploadedFileName, systemHelper.getSupportedUploadedJSExtentions())) {
} else if (checkFileType(fileName, fessConfig.getSupportedUploadedJsExtentionsAsArray())
&& checkFileType(uploadedFileName, fessConfig.getSupportedUploadedJsExtentionsAsArray())) {
baseDir = "/js/";
} else {
throwValidationError(messages -> messages.addErrorsDesignFileIsUnsupportedType("designFileName"), () -> asListHtml());
@ -280,9 +280,9 @@ public class AdminDesignAction extends FessAdminAction implements Serializable {
private List<File> getAccessibleFileList(final File baseDir) {
final List<File> fileList = new ArrayList<File>();
fileList.addAll(FileUtils.listFiles(new File(baseDir, "images"), systemHelper.getSupportedUploadedMediaExtentions(), true));
fileList.addAll(FileUtils.listFiles(new File(baseDir, "css"), systemHelper.getSupportedUploadedCssExtentions(), true));
fileList.addAll(FileUtils.listFiles(new File(baseDir, "js"), systemHelper.getSupportedUploadedJSExtentions(), true));
fileList.addAll(FileUtils.listFiles(new File(baseDir, "images"), fessConfig.getSupportedUploadedMediaExtentionsAsArray(), true));
fileList.addAll(FileUtils.listFiles(new File(baseDir, "css"), fessConfig.getSupportedUploadedCssExtentionsAsArray(), true));
fileList.addAll(FileUtils.listFiles(new File(baseDir, "js"), fessConfig.getSupportedUploadedJsExtentionsAsArray(), true));
return fileList;
}

View file

@ -44,6 +44,7 @@ import org.codelibs.fess.app.service.RoleTypeService;
import org.codelibs.fess.crawler.util.CharUtil;
import org.codelibs.fess.es.config.exentity.RoleType;
import org.codelibs.fess.mylasta.action.FessUserBean;
import org.codelibs.fess.mylasta.direction.FessConfig;
import org.codelibs.fess.util.ComponentUtil;
import org.lastaflute.di.core.SingletonLaContainer;
import org.lastaflute.web.servlet.request.RequestManager;
@ -60,33 +61,21 @@ public class SystemHelper implements Serializable {
private final Set<String> adminRoleSet = new HashSet<>();
private String javaCommandPath = "java";
private String filterPathEncoding = Constants.UTF_8;
private boolean useOwnTmpDir = true;
private String[] supportedHelpLangs = new String[] {};
private final Map<String, String> designJspFileNameMap = new HashMap<String, String>();
private String[] supportedUploadedJSExtentions = new String[] { "js" };
private String[] supportedUploadedCssExtentions = new String[] { "css" };
private String[] supportedUploadedMediaExtentions = new String[] { "jpg", "jpeg", "gif", "png", "swf" };
private int maxTextLength = 4000;
private final AtomicBoolean forceStop = new AtomicBoolean(false);
protected String[] supportedLanguages = new String[] { "ar", "bg", "ca", "da", "de", "el", "en", "es", "eu", "fa", "fi", "fr", "ga",
"gl", "hi", "hu", "hy", "id", "it", "ja", "lv", "ko", "nl", "no", "pt", "ro", "ru", "sv", "th", "tr", "zh_CN", "zh_TW", "zh" };
protected LoadingCache<String, List<Map<String, String>>> langItemsCache;
private String filterPathEncoding;
private String[] supportedLanguages;
@PostConstruct
public void init() {
final FessConfig fessConfig = ComponentUtil.getFessConfig();
filterPathEncoding = fessConfig.getPathEncoding();
supportedLanguages = fessConfig.getSupportedLanguagesAsArray();
langItemsCache =
CacheBuilder.newBuilder().maximumSize(20).expireAfterAccess(1, TimeUnit.HOURS)
.build(new CacheLoader<String, List<Map<String, String>>>() {
@ -173,11 +162,9 @@ public class SystemHelper implements Serializable {
final Locale locale = request.getLocale();
if (locale != null) {
final String lang = locale.getLanguage();
for (final String l : supportedHelpLangs) {
if (l.equals(lang)) {
return url.replaceFirst("\\{lang\\}", lang).replaceFirst("\\{version\\}",
Constants.MAJOR_VERSION + "." + Constants.MINOR_VERSION);
}
if (ComponentUtil.getFessConfig().isOnlineHelpSupportedLang(lang)) {
return url.replaceFirst("\\{lang\\}", lang).replaceFirst("\\{version\\}",
Constants.MAJOR_VERSION + "." + Constants.MINOR_VERSION);
}
}
return getDefaultHelpLink(url);
@ -219,88 +206,6 @@ public class SystemHelper implements Serializable {
return roleList;
}
public String getJavaCommandPath() {
return javaCommandPath;
}
public void setJavaCommandPath(final String javaCommandPath) {
this.javaCommandPath = javaCommandPath;
}
/**
* @return the filterPathEncoding
*/
public String getFilterPathEncoding() {
return filterPathEncoding;
}
/**
* @param filterPathEncoding the filterPathEncoding to set
*/
public void setFilterPathEncoding(final String filterPathEncoding) {
this.filterPathEncoding = filterPathEncoding;
}
/**
* @return the useOwnTmpDir
*/
public boolean isUseOwnTmpDir() {
return useOwnTmpDir;
}
/**
* @param useOwnTmpDir the useOwnTmpDir to set
*/
public void setUseOwnTmpDir(final boolean useOwnTmpDir) {
this.useOwnTmpDir = useOwnTmpDir;
}
/**
* @return the supportedHelpLangs
*/
public String[] getSupportedHelpLangs() {
return supportedHelpLangs;
}
/**
* @param supportedHelpLangs the supportedHelpLangs to set
*/
public void setSupportedHelpLangs(final String[] supportedHelpLangs) {
this.supportedHelpLangs = supportedHelpLangs;
}
public String[] getSupportedUploadedJSExtentions() {
return supportedUploadedJSExtentions;
}
public void setSupportedUploadedJSExtentions(final String[] supportedUploadedJSExtentions) {
this.supportedUploadedJSExtentions = supportedUploadedJSExtentions;
}
public String[] getSupportedUploadedCssExtentions() {
return supportedUploadedCssExtentions;
}
public void setSupportedUploadedCssExtentions(final String[] supportedUploadedCssExtentions) {
this.supportedUploadedCssExtentions = supportedUploadedCssExtentions;
}
public String[] getSupportedUploadedMediaExtentions() {
return supportedUploadedMediaExtentions;
}
public void setSupportedUploadedMediaExtentions(final String[] supportedUploadedMediaExtentions) {
this.supportedUploadedMediaExtentions = supportedUploadedMediaExtentions;
}
public int getMaxTextLength() {
return maxTextLength;
}
public void setMaxTextLength(final int maxTextLength) {
this.maxTextLength = maxTextLength;
}
public boolean isForceStop() {
return forceStop.get();
}
@ -314,7 +219,7 @@ public class SystemHelper implements Serializable {
}
public String abbreviateLongText(final String str) {
return StringUtils.abbreviate(str, maxTextLength);
return StringUtils.abbreviate(str, ComponentUtil.getFessConfig().getMaxLogOutputLengthAsInteger().intValue());
}
public String normalizeLang(final String value) {
@ -347,11 +252,4 @@ public class SystemHelper implements Serializable {
}
}
public String[] getSupportedLanguages() {
return supportedLanguages;
}
public void setSupportedLanguages(final String[] supportedLanguages) {
this.supportedLanguages = supportedLanguages;
}
}

View file

@ -16,11 +16,13 @@
package org.codelibs.fess.job;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.servlet.ServletContext;
@ -232,7 +234,7 @@ public class CrawlJob {
final JobHelper jobHelper = ComponentUtil.getJobHelper();
final FessConfig fessConfig = ComponentUtil.getFessConfig();
cmdList.add(systemHelper.getJavaCommandPath());
cmdList.add(fessConfig.getJavaCommandPath());
// -cp
cmdList.add("-cp");
@ -304,15 +306,13 @@ public class CrawlJob {
.forEach(value -> cmdList.add(value));
File ownTmpDir = null;
if (systemHelper.isUseOwnTmpDir()) {
final String tmpDir = System.getProperty("java.io.tmpdir");
if (StringUtil.isNotBlank(tmpDir)) {
ownTmpDir = new File(tmpDir, "fessTmpDir_" + sessionId);
if (ownTmpDir.mkdirs()) {
cmdList.add("-Djava.io.tmpdir=" + ownTmpDir.getAbsolutePath());
} else {
ownTmpDir = null;
}
final String tmpDir = System.getProperty("java.io.tmpdir");
if (fessConfig.isUseOwnTmpDir() && StringUtil.isNotBlank(tmpDir)) {
ownTmpDir = new File(tmpDir, "fessTmpDir_" + sessionId);
if (ownTmpDir.mkdirs()) {
cmdList.add("-Djava.io.tmpdir=" + ownTmpDir.getAbsolutePath());
} else {
ownTmpDir = null;
}
}
@ -344,13 +344,24 @@ public class CrawlJob {
cmdList.add(Integer.toString(documentExpires));
}
final File baseDir = new File(servletContext.getRealPath("/WEB-INF")).getParentFile();
if (logger.isInfoEnabled()) {
logger.info("Crawler: \nDirectory=" + baseDir + "\nOptions=" + cmdList);
}
try {
cmdList.add("-p");
File propFile =
new File(ownTmpDir != null ? ownTmpDir.getAbsolutePath() : tmpDir, "crawler_" + systemHelper.getCurrentTimeAsLong()
+ ".properties");
cmdList.add(propFile.getAbsolutePath());
try (FileOutputStream out = new FileOutputStream(propFile)) {
Properties prop = new Properties();
prop.putAll(ComponentUtil.getCrawlerProperties());
prop.store(out, cmdList.toString());
}
final File baseDir = new File(servletContext.getRealPath("/WEB-INF")).getParentFile();
if (logger.isInfoEnabled()) {
logger.info("Crawler: \nDirectory=" + baseDir + "\nOptions=" + cmdList);
}
final JobProcess jobProcess = jobHelper.startProcess(sessionId, cmdList, pb -> {
pb.directory(baseDir);
pb.redirectErrorStream(true);

View file

@ -16,11 +16,13 @@
package org.codelibs.fess.job;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import javax.servlet.ServletContext;
@ -125,7 +127,7 @@ public class SuggestJob {
final JobHelper jobHelper = ComponentUtil.getJobHelper();
final FessConfig fessConfig = ComponentUtil.getFessConfig();
cmdList.add(systemHelper.getJavaCommandPath());
cmdList.add(fessConfig.getJavaCommandPath());
// -cp
cmdList.add("-cp");
@ -201,15 +203,13 @@ public class SuggestJob {
.forEach(value -> cmdList.add(value));
File ownTmpDir = null;
if (systemHelper.isUseOwnTmpDir()) {
final String tmpDir = System.getProperty("java.io.tmpdir");
if (StringUtil.isNotBlank(tmpDir)) {
ownTmpDir = new File(tmpDir, "fessTmpDir_" + sessionId);
if (ownTmpDir.mkdirs()) {
cmdList.add("-Djava.io.tmpdir=" + ownTmpDir.getAbsolutePath());
} else {
ownTmpDir = null;
}
final String tmpDir = System.getProperty("java.io.tmpdir");
if (fessConfig.isUseOwnTmpDir() && StringUtil.isNotBlank(tmpDir)) {
ownTmpDir = new File(tmpDir, "fessTmpDir_" + sessionId);
if (ownTmpDir.mkdirs()) {
cmdList.add("-Djava.io.tmpdir=" + ownTmpDir.getAbsolutePath());
} else {
ownTmpDir = null;
}
}
@ -218,13 +218,24 @@ public class SuggestJob {
cmdList.add("--sessionId");
cmdList.add(sessionId);
final File baseDir = new File(servletContext.getRealPath("/WEB-INF")).getParentFile();
if (logger.isInfoEnabled()) {
logger.info("SuggestCreator: \nDirectory=" + baseDir + "\nOptions=" + cmdList);
}
try {
cmdList.add("-p");
File propFile =
new File(ownTmpDir != null ? ownTmpDir.getAbsolutePath() : tmpDir, "crawler_" + systemHelper.getCurrentTimeAsLong()
+ ".properties");
cmdList.add(propFile.getAbsolutePath());
try (FileOutputStream out = new FileOutputStream(propFile)) {
Properties prop = new Properties();
prop.putAll(ComponentUtil.getCrawlerProperties());
prop.store(out, cmdList.toString());
}
final File baseDir = new File(servletContext.getRealPath("/WEB-INF")).getParentFile();
if (logger.isInfoEnabled()) {
logger.info("SuggestCreator: \nDirectory=" + baseDir + "\nOptions=" + cmdList);
}
final JobProcess jobProcess = jobHelper.startProcess(sessionId, cmdList, pb -> {
pb.directory(baseDir);
pb.redirectErrorStream(true);

View file

@ -69,6 +69,30 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
/** The key of the configuration. e.g. default_crawler */
String JOB_SYSTEM_JOB_IDS = "job.system.job.ids";
/** The key of the configuration. e.g. java */
String JAVA_COMMAND_PATH = "java.command.path";
/** The key of the configuration. e.g. UTF-8 */
String PATH_ENCODING = "path.encoding";
/** The key of the configuration. e.g. true */
String USE_OWN_TMP_DIR = "use.own.tmp.dir";
/** The key of the configuration. e.g. 4000 */
String MAX_LOG_OUTPUT_LENGTH = "max.log.output.length";
/** The key of the configuration. e.g. js */
String SUPPORTED_UPLOADED_JS_EXTENTIONS = "supported.uploaded.js.extentions";
/** The key of the configuration. e.g. css */
String SUPPORTED_UPLOADED_CSS_EXTENTIONS = "supported.uploaded.css.extentions";
/** The key of the configuration. e.g. jpg,jpeg,gif,png,swf */
String SUPPORTED_UPLOADED_MEDIA_EXTENTIONS = "supported.uploaded.media.extentions";
/** The key of the configuration. e.g. ar,bg,ca,da,de,el,en,es,eu,fa,fi,fr,ga,gl,hi,hu,hy,id,it,ja,lv,ko,nl,no,pt,ro,ru,sv,th,tr,zh_CN,zh_TW,zh */
String SUPPORTED_LANGUAGES = "supported.languages";
/** The key of the configuration. e.g. 50 */
String CRAWLER_DOCUMENT_MAX_SITE_LENGTH = "crawler.document.max.site.length";
@ -447,6 +471,9 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
/** The key of the configuration. e.g. backup */
String ONLINE_HELP_NAME_BACKUP = "online.help.name.backup";
/** The key of the configuration. e.g. */
String ONLINE_HELP_SUPPORTED_LANGS = "online.help.supported.langs";
/** The key of the configuration. e.g. 0 */
String SUGGEST_POPULAR_WORD_SEED = "suggest.popular.word.seed";
@ -590,6 +617,77 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
*/
String getJobSystemJobIds();
/**
* Get the value for the key 'java.command.path'. <br>
* The value is, e.g. java <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getJavaCommandPath();
/**
* Get the value for the key 'path.encoding'. <br>
* The value is, e.g. UTF-8 <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getPathEncoding();
/**
* Get the value for the key 'use.own.tmp.dir'. <br>
* The value is, e.g. true <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getUseOwnTmpDir();
/**
* Is the property for the key 'use.own.tmp.dir' true? <br>
* The value is, e.g. true <br>
* @return The determination, true or false. (if not found, exception but basically no way)
*/
boolean isUseOwnTmpDir();
/**
* Get the value for the key 'max.log.output.length'. <br>
* The value is, e.g. 4000 <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getMaxLogOutputLength();
/**
* Get the value for the key 'max.log.output.length' as {@link Integer}. <br>
* The value is, e.g. 4000 <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
* @throws NumberFormatException When the property is not integer.
*/
Integer getMaxLogOutputLengthAsInteger();
/**
* Get the value for the key 'supported.uploaded.js.extentions'. <br>
* The value is, e.g. js <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getSupportedUploadedJsExtentions();
/**
* Get the value for the key 'supported.uploaded.css.extentions'. <br>
* The value is, e.g. css <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getSupportedUploadedCssExtentions();
/**
* Get the value for the key 'supported.uploaded.media.extentions'. <br>
* The value is, e.g. jpg,jpeg,gif,png,swf <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getSupportedUploadedMediaExtentions();
/**
* Get the value for the key 'supported.languages'. <br>
* The value is, e.g. ar,bg,ca,da,de,el,en,es,eu,fa,fi,fr,ga,gl,hi,hu,hy,id,it,ja,lv,ko,nl,no,pt,ro,ru,sv,th,tr,zh_CN,zh_TW,zh <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getSupportedLanguages();
/**
* Get the value for the key 'crawler.document.max.site.length'. <br>
* The value is, e.g. 50 <br>
@ -1867,6 +1965,21 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
*/
String getOnlineHelpNameBackup();
/**
* Get the value for the key 'online.help.supported.langs'. <br>
* The value is, e.g. <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
*/
String getOnlineHelpSupportedLangs();
/**
* Get the value for the key 'online.help.supported.langs' as {@link Integer}. <br>
* The value is, e.g. <br>
* @return The value of found property. (NotNull: if not found, exception but basically no way)
* @throws NumberFormatException When the property is not integer.
*/
Integer getOnlineHelpSupportedLangsAsInteger();
/**
* Get the value for the key 'suggest.popular.word.seed'. <br>
* The value is, e.g. 0 <br>
@ -2069,6 +2182,46 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
return get(FessConfig.JOB_SYSTEM_JOB_IDS);
}
public String getJavaCommandPath() {
return get(FessConfig.JAVA_COMMAND_PATH);
}
public String getPathEncoding() {
return get(FessConfig.PATH_ENCODING);
}
public String getUseOwnTmpDir() {
return get(FessConfig.USE_OWN_TMP_DIR);
}
public boolean isUseOwnTmpDir() {
return is(FessConfig.USE_OWN_TMP_DIR);
}
public String getMaxLogOutputLength() {
return get(FessConfig.MAX_LOG_OUTPUT_LENGTH);
}
public Integer getMaxLogOutputLengthAsInteger() {
return getAsInteger(FessConfig.MAX_LOG_OUTPUT_LENGTH);
}
public String getSupportedUploadedJsExtentions() {
return get(FessConfig.SUPPORTED_UPLOADED_JS_EXTENTIONS);
}
public String getSupportedUploadedCssExtentions() {
return get(FessConfig.SUPPORTED_UPLOADED_CSS_EXTENTIONS);
}
public String getSupportedUploadedMediaExtentions() {
return get(FessConfig.SUPPORTED_UPLOADED_MEDIA_EXTENTIONS);
}
public String getSupportedLanguages() {
return get(FessConfig.SUPPORTED_LANGUAGES);
}
public String getCrawlerDocumentMaxSiteLength() {
return get(FessConfig.CRAWLER_DOCUMENT_MAX_SITE_LENGTH);
}
@ -2757,6 +2910,14 @@ public interface FessConfig extends FessEnv, org.codelibs.fess.mylasta.direction
return get(FessConfig.ONLINE_HELP_NAME_BACKUP);
}
public String getOnlineHelpSupportedLangs() {
return get(FessConfig.ONLINE_HELP_SUPPORTED_LANGS);
}
public Integer getOnlineHelpSupportedLangsAsInteger() {
return getAsInteger(FessConfig.ONLINE_HELP_SUPPORTED_LANGS);
}
public String getSuggestPopularWordSeed() {
return get(FessConfig.SUGGEST_POPULAR_WORD_SEED);
}

View file

@ -150,4 +150,40 @@ public interface FessProp {
return s.equals(value);
});
}
String getSupportedLanguages();
public default String[] getSupportedLanguagesAsArray() {
return StreamUtil.of(getSupportedLanguages().split(",")).filter(s -> StringUtil.isNotBlank(s)).toArray(n -> new String[n]);
}
String getOnlineHelpSupportedLangs();
public default boolean isOnlineHelpSupportedLang(String lang) {
if (StringUtil.isBlank(getOnlineHelpSupportedLangs())) {
return false;
}
return StreamUtil.of(getOnlineHelpSupportedLangs().split(",")).filter(s -> StringUtil.isNotBlank(s)).anyMatch(s -> s.equals(lang));
}
String getSupportedUploadedJsExtentions();
public default String[] getSupportedUploadedJsExtentionsAsArray() {
return StreamUtil.of(getSupportedUploadedJsExtentions().split(",")).filter(s -> StringUtil.isNotBlank(s))
.toArray(n -> new String[n]);
}
String getSupportedUploadedCssExtentions();
public default String[] getSupportedUploadedCssExtentionsAsArray() {
return StreamUtil.of(getSupportedUploadedCssExtentions().split(",")).filter(s -> StringUtil.isNotBlank(s))
.toArray(n -> new String[n]);
}
String getSupportedUploadedMediaExtentions();
public default String[] getSupportedUploadedMediaExtentionsAsArray() {
return StreamUtil.of(getSupportedUploadedMediaExtentions().split(",")).filter(s -> StringUtil.isNotBlank(s))
.toArray(n -> new String[n]);
}
}

View file

@ -49,6 +49,16 @@ jvm.suggest.options=\
# job
job.system.job.ids=default_crawler
java.command.path=java
path.encoding=UTF-8
use.own.tmp.dir=true
max.log.output.length=4000
supported.uploaded.js.extentions=js
supported.uploaded.css.extentions=css
supported.uploaded.media.extentions=jpg,jpeg,gif,png,swf
supported.languages=ar,bg,ca,da,de,el,en,es,eu,fa,fi,fr,ga,gl,hi,hu,hy,id,it,ja,lv,ko,nl,no,pt,ro,ru,sv,th,tr,zh_CN,zh_TW,zh
# ========================================================================================
# Index
# ====
@ -247,6 +257,8 @@ online.help.name.scheduler=scheduler
online.help.name.crawlinginfo=crawlinginfo
online.help.name.backup=backup
online.help.supported.langs=
# ----------------------------------------------------------
# Suggest
# ------