You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opennlp.apache.org by rz...@apache.org on 2023/01/02 19:03:49 UTC
[opennlp] branch main updated: OPENNLP-1428 - Enhance DownloadUtil to avoid the use of hard-coded model urls
This is an automated email from the ASF dual-hosted git repository.
rzo1 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/opennlp.git
The following commit(s) were added to refs/heads/main by this push:
new c270b99b OPENNLP-1428 - Enhance DownloadUtil to avoid the use of hard-coded model urls
c270b99b is described below
commit c270b99b914baedb13045c5d5eaa9b5f11c9c999
Author: Richard Zowalla <rz...@apache.org>
AuthorDate: Fri Dec 30 13:15:31 2022 +0100
OPENNLP-1428 - Enhance DownloadUtil to avoid the use of hard-coded model urls
---
.../main/java/opennlp/tools/util/DownloadUtil.java | 141 ++++++++++++++-------
.../opennlp/tools/util/DownloadParserTest.java | 114 +++++++++++++++++
.../test/resources/opennlp/tools/util/index.html | 99 +++++++++++++++
3 files changed, 307 insertions(+), 47 deletions(-)
diff --git a/opennlp-tools/src/main/java/opennlp/tools/util/DownloadUtil.java b/opennlp-tools/src/main/java/opennlp/tools/util/DownloadUtil.java
index cbc36108..41aed090 100644
--- a/opennlp-tools/src/main/java/opennlp/tools/util/DownloadUtil.java
+++ b/opennlp-tools/src/main/java/opennlp/tools/util/DownloadUtil.java
@@ -17,16 +17,26 @@
package opennlp.tools.util;
+import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
import java.net.URL;
+import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
+import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import opennlp.tools.commons.Internal;
import opennlp.tools.util.model.BaseModel;
/**
@@ -55,55 +65,14 @@ public class DownloadUtil {
private static final String BASE_URL = "https://dlcdn.apache.org/opennlp/";
private static final String MODELS_UD_MODELS_1_0 = "models/ud-models-1.0/";
- public static final Map<String, Map<ModelType, String>> available_models = new HashMap<>();
+ public static final Map<String, Map<ModelType, String>> available_models;
static {
-
- final Map<ModelType, String> frenchModels = new HashMap<>();
- frenchModels.put(ModelType.SENTENCE_DETECTOR,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-1.0-1.9.3fr-ud-ftb-sentence-1.0-1.9.3.bin");
- frenchModels.put(ModelType.POS,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-fr-ud-ftb-pos-1.0-1.9.3.bin");
- frenchModels.put(ModelType.TOKENIZER,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-fr-ud-ftb-tokens-1.0-1.9.3.bin");
- available_models.put("fr", frenchModels);
-
- final Map<ModelType, String> germanModels = new HashMap<>();
- germanModels.put(ModelType.SENTENCE_DETECTOR,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-de-ud-gsd-sentence-1.0-1.9.3.bin");
- germanModels.put(ModelType.POS,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-de-ud-gsd-pos-1.0-1.9.3.bin");
- germanModels.put(ModelType.TOKENIZER,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-de-ud-gsd-tokens-1.0-1.9.3.bin");
- available_models.put("de", germanModels);
-
- final Map<ModelType, String> englishModels = new HashMap<>();
- englishModels.put(ModelType.SENTENCE_DETECTOR,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin");
- englishModels.put(ModelType.POS,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-en-ud-ewt-pos-1.0-1.9.3.bin");
- englishModels.put(ModelType.TOKENIZER,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-en-ud-ewt-tokens-1.0-1.9.3.bin");
- available_models.put("en", englishModels);
-
- final Map<ModelType, String> italianModels = new HashMap<>();
- italianModels.put(ModelType.SENTENCE_DETECTOR,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-it-ud-vit-sentence-1.0-1.9.3.bin");
- italianModels.put(ModelType.POS,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-it-ud-vit-pos-1.0-1.9.3.bin");
- italianModels.put(ModelType.TOKENIZER,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-it-ud-vit-tokens-1.0-1.9.3.bin");
- available_models.put("it", italianModels);
-
- final Map<ModelType, String> dutchModels = new HashMap<>();
- dutchModels.put(ModelType.SENTENCE_DETECTOR,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-nl-ud-alpino-sentence-1.0-1.9.3.bin");
- dutchModels.put(ModelType.POS,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-nl-ud-alpino-pos-1.0-1.9.3.bin");
- dutchModels.put(ModelType.TOKENIZER,
- BASE_URL + MODELS_UD_MODELS_1_0 + "opennlp-nl-ud-alpino-tokens-1.0-1.9.3.bin");
- available_models.put("nl", dutchModels);
-
+ try {
+ available_models = new DownloadParser(new URL(BASE_URL + MODELS_UD_MODELS_1_0)).getAvailableModels();
+ } catch (MalformedURLException e) {
+ throw new RuntimeException(e);
+ }
}
/**
@@ -174,4 +143,82 @@ public class DownloadUtil {
}
}
+ @Internal
+ static class DownloadParser {
+
+ private static final Pattern LINK_PATTERN = Pattern.compile("<a href=\\\"(.*?)\\\">(.*?)</a>", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
+ private final URL indexUrl;
+
+ DownloadParser(URL indexUrl) {
+ Objects.requireNonNull(indexUrl);
+ this.indexUrl = indexUrl;
+ }
+
+ Map<String, Map<ModelType, String>> getAvailableModels() {
+
+ final Matcher matcher = LINK_PATTERN.matcher(fetchPageIndex());
+
+ final List<String> links = new ArrayList<>();
+ while (matcher.find()) {
+ links.add(matcher.group(1));
+ }
+
+ return toMap(links);
+ }
+
+ private Map<String, Map<ModelType, String>> toMap(List<String> links) {
+
+ final Map<String, Map<ModelType, String>> result = new HashMap<>();
+
+ for (String link : links) {
+
+ if (link.endsWith(".bin")) {
+ if (link.contains("de-ud")) {
+ addModel("de", link, result);
+ } else if (link.contains("en-ud")) {
+ addModel("en", link, result);
+ } else if (link.contains("it-ud")) {
+ addModel("it", link, result);
+ } else if (link.contains("nl-ud")) {
+ addModel("nl", link, result);
+ } else if (link.contains("fr-ud")) {
+ addModel("fr", link, result);
+ }
+ }
+
+ }
+
+ return result;
+ }
+
+ private void addModel(String locale, String link, Map<String, Map<ModelType, String>> result) {
+ final Map<ModelType, String> models = result.getOrDefault(locale, new HashMap<>());
+ final String url = (indexUrl.toString().endsWith("/") ? indexUrl : indexUrl + "/") + link;
+
+ if (link.contains("sentence")) {
+ models.put(ModelType.SENTENCE_DETECTOR, url);
+ } else if (link.contains("tokens")) {
+ models.put(ModelType.TOKENIZER, url);
+ } else if (link.contains("pos")) {
+ models.put(ModelType.POS, url);
+ }
+
+ result.putIfAbsent(locale, models);
+ }
+
+ private String fetchPageIndex() {
+ final StringBuilder html = new StringBuilder();
+ try (BufferedReader br = new BufferedReader(
+ new InputStreamReader(indexUrl.openStream(), StandardCharsets.UTF_8))) {
+ String line;
+ while ((line = br.readLine()) != null) {
+ html.append(line);
+ }
+ } catch (IOException e) {
+ System.err.println("Could not read page index from " + indexUrl);
+ }
+
+ return html.toString();
+ }
+ }
}
diff --git a/opennlp-tools/src/test/java/opennlp/tools/util/DownloadParserTest.java b/opennlp-tools/src/test/java/opennlp/tools/util/DownloadParserTest.java
new file mode 100644
index 00000000..0d62e69b
--- /dev/null
+++ b/opennlp-tools/src/test/java/opennlp/tools/util/DownloadParserTest.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package opennlp.tools.util;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Map;
+import java.util.stream.Stream;
+
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+public class DownloadParserTest {
+
+ @ParameterizedTest(name = "Verify \"{0}\" available models")
+ @MethodSource(value = "expectedModels")
+ void testAvailableModels(String language, Map<DownloadUtil.ModelType, String> expectedModels) {
+
+ final URL baseUrl = fromClasspath("opennlp/tools/util/index.html");
+ assertNotNull(baseUrl);
+
+ final DownloadUtil.DownloadParser downloadParser = new DownloadUtil.DownloadParser(baseUrl);
+
+ Map<String, Map<DownloadUtil.ModelType, String>> result = downloadParser.getAvailableModels();
+
+ assertNotNull(result);
+ assertEquals(5, result.size());
+
+ final Map<DownloadUtil.ModelType, String> availableModels = result.get(language);
+ assertNotNull(availableModels);
+
+ for (Map.Entry<DownloadUtil.ModelType, String> e : expectedModels.entrySet()) {
+ final String url = availableModels.get(e.getKey());
+ final String expectedUrl = baseUrl + "/" + e.getValue();
+
+ assertNotNull(url, "A model for the given model type is expected");
+ assertEquals(expectedUrl, url);
+ }
+ }
+
+ @Test
+ void testNullUrl() {
+ assertThrows(NullPointerException.class, () -> {
+ new DownloadUtil.DownloadParser(null);
+ }
+ );
+ }
+
+ @Test
+ void testInvalidUrl() throws MalformedURLException {
+ final DownloadUtil.DownloadParser downloadParser =
+ new DownloadUtil.DownloadParser(new URL("file:/this/does/not/exist"));
+ Map<String, Map<DownloadUtil.ModelType, String>> result = downloadParser.getAvailableModels();
+ assertNotNull(result);
+ assertEquals(0, result.size());
+ }
+
+ private URL fromClasspath(String file) {
+ return Thread.currentThread().getContextClassLoader().getResource(file);
+ }
+
+ // Note: This needs to be public as JUnit 5 requires it like this.
+ public static Stream<Arguments> expectedModels() {
+ // Data as defined in "test/resources/opennlp/tools/util/index.html"
+ return Stream.of(
+ Arguments.of("en",
+ Map.of(
+ DownloadUtil.ModelType.SENTENCE_DETECTOR, "opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin",
+ DownloadUtil.ModelType.TOKENIZER, "opennlp-en-ud-ewt-tokens-1.0-1.9.3.bin",
+ DownloadUtil.ModelType.POS, "opennlp-en-ud-ewt-pos-1.0-1.9.3.bin")),
+ Arguments.of("fr",
+ Map.of(
+ DownloadUtil.ModelType.SENTENCE_DETECTOR, "opennlp-1.0-1.9.3fr-ud-ftb-sentence-1.0-1.9.3.bin",
+ DownloadUtil.ModelType.TOKENIZER, "opennlp-fr-ud-ftb-tokens-1.0-1.9.3.bin",
+ DownloadUtil.ModelType.POS, "opennlp-fr-ud-ftb-pos-1.0-1.9.3.bin")),
+ Arguments.of("de",
+ Map.of(
+ DownloadUtil.ModelType.SENTENCE_DETECTOR, "opennlp-de-ud-gsd-sentence-1.0-1.9.3.bin",
+ DownloadUtil.ModelType.TOKENIZER, "opennlp-de-ud-gsd-tokens-1.0-1.9.3.bin",
+ DownloadUtil.ModelType.POS, "opennlp-de-ud-gsd-pos-1.0-1.9.3.bin")),
+ Arguments.of("it",
+ Map.of(
+ DownloadUtil.ModelType.SENTENCE_DETECTOR, "opennlp-it-ud-vit-sentence-1.0-1.9.3.bin",
+ DownloadUtil.ModelType.TOKENIZER, "opennlp-it-ud-vit-tokens-1.0-1.9.3.bin",
+ DownloadUtil.ModelType.POS, "opennlp-it-ud-vit-pos-1.0-1.9.3.bin")),
+ Arguments.of("nl",
+ Map.of(
+ DownloadUtil.ModelType.SENTENCE_DETECTOR, "opennlp-nl-ud-alpino-sentence-1.0-1.9.3.bin",
+ DownloadUtil.ModelType.TOKENIZER, "opennlp-nl-ud-alpino-tokens-1.0-1.9.3.bin",
+ DownloadUtil.ModelType.POS, "opennlp-nl-ud-alpino-pos-1.0-1.9.3.bin"))
+ );
+ }
+}
diff --git a/opennlp-tools/src/test/resources/opennlp/tools/util/index.html b/opennlp-tools/src/test/resources/opennlp/tools/util/index.html
new file mode 100644
index 00000000..fd77cfd6
--- /dev/null
+++ b/opennlp-tools/src/test/resources/opennlp/tools/util/index.html
@@ -0,0 +1,99 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<!--
+This is a copy of https://dlcdn.apache.org/opennlp/models/ud-models-1.0/ used for testing the DownloadParser
+-->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+ <head>
+ <title>Index of /opennlp/models/ud-models-1.0</title>
+ </head>
+ <body>
+<h1>Index of /opennlp/models/ud-models-1.0</h1>
+<pre><img src="/icons/blank.gif" alt="Icon "> <a href="?C=N;O=D">Name</a> <a href="?C=M;O=A">Last modified</a> <a href="?C=S;O=A">Size</a> <a href="?C=D;O=A">Description</a><hr><img src="/icons/back.gif" alt="[PARENTDIR]"> <a href="/opennlp/models/">Parent Directory</a> -
+<img src="/icons/unknown.gif" alt="[ ]"> <a href="CHANGES">CHANGES</a> 2021-05-29 13:55 581
+<img src="/icons/unknown.gif" alt="[ ]"> <a href="LICENSE">LICENSE</a> 2021-05-29 13:55 13K
+<img src="/icons/unknown.gif" alt="[ ]"> <a href="NOTICE">NOTICE</a> 2021-05-29 13:55 376
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-1.0-1.9.3fr-ud-ftb-sentence-1.0-1.9.3.bin">opennlp-1.0-1.9.3fr-ud-ftb-sentence-1.0-1.9.3.bin</a> 2021-05-29 13:55 846
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-1.0-1.9.3fr-ud-ftb-sentence-1.0-1.9.3.bin.asc">opennlp-1.0-1.9.3fr-ud-ftb-sentence-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-1.0-1.9.3fr-ud-ftb-sentence-1.0-1.9.3.bin.sha256">opennlp-1.0-1.9.3fr-ud-ftb-sentence-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 118
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-1.0-1.9.3fr-ud-ftb-sentence-1.0-1.9.3.bin.sha512">opennlp-1.0-1.9.3fr-ud-ftb-sentence-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 182
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-de-ud-gsd-pos-1.0-1.9.3.bin">opennlp-de-ud-gsd-pos-1.0-1.9.3.bin</a> 2021-05-29 13:55 1.2M
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-de-ud-gsd-pos-1.0-1.9.3.bin.asc">opennlp-de-ud-gsd-pos-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-de-ud-gsd-pos-1.0-1.9.3.bin.sha256">opennlp-de-ud-gsd-pos-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 104
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-de-ud-gsd-pos-1.0-1.9.3.bin.sha512">opennlp-de-ud-gsd-pos-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 168
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-de-ud-gsd-sentence-1.0-1.9.3.bin">opennlp-de-ud-gsd-sentence-1.0-1.9.3.bin</a> 2021-05-29 13:55 15K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-de-ud-gsd-sentence-1.0-1.9.3.bin.asc">opennlp-de-ud-gsd-sentence-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-de-ud-gsd-sentence-1.0-1.9.3.bin.sha256">opennlp-de-ud-gsd-sentence-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 109
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-de-ud-gsd-sentence-1.0-1.9.3.bin.sha512">opennlp-de-ud-gsd-sentence-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 173
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-de-ud-gsd-tokens-1.0-1.9.3.bin">opennlp-de-ud-gsd-tokens-1.0-1.9.3.bin</a> 2021-05-29 13:55 553K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-de-ud-gsd-tokens-1.0-1.9.3.bin.asc">opennlp-de-ud-gsd-tokens-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-de-ud-gsd-tokens-1.0-1.9.3.bin.sha256">opennlp-de-ud-gsd-tokens-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 107
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-de-ud-gsd-tokens-1.0-1.9.3.bin.sha512">opennlp-de-ud-gsd-tokens-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 171
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-en-ud-ewt-pos-1.0-1.9.3.bin">opennlp-en-ud-ewt-pos-1.0-1.9.3.bin</a> 2021-05-29 13:55 1.1M
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-en-ud-ewt-pos-1.0-1.9.3.bin.asc">opennlp-en-ud-ewt-pos-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-en-ud-ewt-pos-1.0-1.9.3.bin.sha256">opennlp-en-ud-ewt-pos-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 104
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-en-ud-ewt-pos-1.0-1.9.3.bin.sha512">opennlp-en-ud-ewt-pos-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 168
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin">opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin</a> 2021-05-29 13:55 20K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin.asc">opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin.sha256">opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 109
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin.sha512">opennlp-en-ud-ewt-sentence-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 173
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-en-ud-ewt-tokens-1.0-1.9.3.bin">opennlp-en-ud-ewt-tokens-1.0-1.9.3.bin</a> 2021-05-29 13:55 338K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-en-ud-ewt-tokens-1.0-1.9.3.bin.asc">opennlp-en-ud-ewt-tokens-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-en-ud-ewt-tokens-1.0-1.9.3.bin.sha256">opennlp-en-ud-ewt-tokens-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 107
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-en-ud-ewt-tokens-1.0-1.9.3.bin.sha512">opennlp-en-ud-ewt-tokens-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 171
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-fr-ud-ftb-pos-1.0-1.9.3.bin">opennlp-fr-ud-ftb-pos-1.0-1.9.3.bin</a> 2021-05-29 13:55 72K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-fr-ud-ftb-pos-1.0-1.9.3.bin.asc">opennlp-fr-ud-ftb-pos-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-fr-ud-ftb-pos-1.0-1.9.3.bin.sha256">opennlp-fr-ud-ftb-pos-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 104
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-fr-ud-ftb-pos-1.0-1.9.3.bin.sha512">opennlp-fr-ud-ftb-pos-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 168
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-fr-ud-ftb-tokens-1.0-1.9.3.bin">opennlp-fr-ud-ftb-tokens-1.0-1.9.3.bin</a> 2021-05-29 13:55 35K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-fr-ud-ftb-tokens-1.0-1.9.3.bin.asc">opennlp-fr-ud-ftb-tokens-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-fr-ud-ftb-tokens-1.0-1.9.3.bin.sha256">opennlp-fr-ud-ftb-tokens-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 107
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-fr-ud-ftb-tokens-1.0-1.9.3.bin.sha512">opennlp-fr-ud-ftb-tokens-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 171
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-it-ud-vit-pos-1.0-1.9.3.bin">opennlp-it-ud-vit-pos-1.0-1.9.3.bin</a> 2021-05-29 13:55 1.1M
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-it-ud-vit-pos-1.0-1.9.3.bin.asc">opennlp-it-ud-vit-pos-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-it-ud-vit-pos-1.0-1.9.3.bin.sha256">opennlp-it-ud-vit-pos-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 104
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-it-ud-vit-pos-1.0-1.9.3.bin.sha512">opennlp-it-ud-vit-pos-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 168
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-it-ud-vit-sentence-1.0-1.9.3.bin">opennlp-it-ud-vit-sentence-1.0-1.9.3.bin</a> 2021-05-29 13:55 9.4K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-it-ud-vit-sentence-1.0-1.9.3.bin.asc">opennlp-it-ud-vit-sentence-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-it-ud-vit-sentence-1.0-1.9.3.bin.sha256">opennlp-it-ud-vit-sentence-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 109
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-it-ud-vit-sentence-1.0-1.9.3.bin.sha512">opennlp-it-ud-vit-sentence-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 173
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-it-ud-vit-tokens-1.0-1.9.3.bin">opennlp-it-ud-vit-tokens-1.0-1.9.3.bin</a> 2021-05-29 13:55 387K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-it-ud-vit-tokens-1.0-1.9.3.bin.asc">opennlp-it-ud-vit-tokens-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-it-ud-vit-tokens-1.0-1.9.3.bin.sha256">opennlp-it-ud-vit-tokens-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 107
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-it-ud-vit-tokens-1.0-1.9.3.bin.sha512">opennlp-it-ud-vit-tokens-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 171
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-nl-ud-alpino-pos-1.0-1.9.3.bin">opennlp-nl-ud-alpino-pos-1.0-1.9.3.bin</a> 2021-05-29 13:55 897K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-nl-ud-alpino-pos-1.0-1.9.3.bin.asc">opennlp-nl-ud-alpino-pos-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-nl-ud-alpino-pos-1.0-1.9.3.bin.sha256">opennlp-nl-ud-alpino-pos-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 107
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-nl-ud-alpino-pos-1.0-1.9.3.bin.sha512">opennlp-nl-ud-alpino-pos-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 171
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-nl-ud-alpino-sentence-1.0-1.9.3.bin">opennlp-nl-ud-alpino-sentence-1.0-1.9.3.bin</a> 2021-05-29 13:55 13K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-nl-ud-alpino-sentence-1.0-1.9.3.bin.asc">opennlp-nl-ud-alpino-sentence-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-nl-ud-alpino-sentence-1.0-1.9.3.bin.sha256">opennlp-nl-ud-alpino-sentence-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 112
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-nl-ud-alpino-sentence-1.0-1.9.3.bin.sha512">opennlp-nl-ud-alpino-sentence-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 176
+<img src="/icons/binary.gif" alt="[ ]"> <a href="opennlp-nl-ud-alpino-tokens-1.0-1.9.3.bin">opennlp-nl-ud-alpino-tokens-1.0-1.9.3.bin</a> 2021-05-29 13:55 340K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-nl-ud-alpino-tokens-1.0-1.9.3.bin.asc">opennlp-nl-ud-alpino-tokens-1.0-1.9.3.bin.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-nl-ud-alpino-tokens-1.0-1.9.3.bin.sha256">opennlp-nl-ud-alpino-tokens-1.0-1.9.3.bin.sha256</a> 2021-05-29 13:55 110
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-nl-ud-alpino-tokens-1.0-1.9.3.bin.sha512">opennlp-nl-ud-alpino-tokens-1.0-1.9.3.bin.sha512</a> 2021-05-29 13:55 174
+<img src="/icons/compressed.gif" alt="[ ]"> <a href="opennlp-training-eval-logs-1.0-1.9.3.zip">opennlp-training-eval-logs-1.0-1.9.3.zip</a> 2021-05-29 13:55 40K
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-training-eval-logs-1.0-1.9.3.zip.asc">opennlp-training-eval-logs-1.0-1.9.3.zip.asc</a> 2021-05-29 13:55 833
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-training-eval-logs-1.0-1.9.3.zip.sha256">opennlp-training-eval-logs-1.0-1.9.3.zip.sha256</a> 2021-05-29 13:55 109
+<img src="/icons/text.gif" alt="[TXT]"> <a href="opennlp-training-eval-logs-1.0-1.9.3.zip.sha512">opennlp-training-eval-logs-1.0-1.9.3.zip.sha512</a> 2021-05-29 13:55 173
+<hr></pre>
+</body></html>
+