| margaretha | 398f472 | 2019-01-09 19:07:20 +0100 | [diff] [blame] | 1 | package de.ids_mannheim.korap.rewrite; |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 2 | |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 3 | import static org.junit.jupiter.api.Assertions.assertEquals; |
| 4 | import static org.junit.jupiter.api.Assertions.assertFalse; |
| 5 | import static org.junit.jupiter.api.Assertions.assertNotNull; |
| 6 | import static org.junit.jupiter.api.Assertions.assertTrue; |
| margaretha | f68daa6 | 2017-09-21 02:11:24 +0200 | [diff] [blame] | 7 | |
| margaretha | a9f5299 | 2025-06-24 11:50:15 +0200 | [diff] [blame] | 8 | import java.util.HashMap; |
| 9 | import java.util.Map; |
| 10 | |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 11 | import org.junit.jupiter.api.Test; |
| margaretha | 5c67dd5 | 2018-12-18 17:27:05 +0100 | [diff] [blame] | 12 | import org.springframework.beans.factory.annotation.Autowired; |
| margaretha | a9f5299 | 2025-06-24 11:50:15 +0200 | [diff] [blame] | 13 | |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 14 | import com.fasterxml.jackson.databind.JsonNode; |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 15 | |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 16 | import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler; |
| 17 | import de.ids_mannheim.korap.config.Attributes; |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 18 | import de.ids_mannheim.korap.config.KustvaktConfiguration; |
| margaretha | a9f5299 | 2025-06-24 11:50:15 +0200 | [diff] [blame] | 19 | import de.ids_mannheim.korap.config.TestBase; |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 20 | import de.ids_mannheim.korap.exceptions.KustvaktException; |
| Michael Hanl | badd79c | 2015-06-19 07:41:03 +0200 | [diff] [blame] | 21 | import de.ids_mannheim.korap.query.serialize.QuerySerializer; |
| margaretha | 5c67dd5 | 2018-12-18 17:27:05 +0100 | [diff] [blame] | 22 | import de.ids_mannheim.korap.user.KorAPUser; |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 23 | import de.ids_mannheim.korap.utils.JsonUtils; |
| margaretha | 96c309d | 2023-08-16 12:24:12 +0200 | [diff] [blame] | 24 | import jakarta.ws.rs.client.Entity; |
| 25 | import jakarta.ws.rs.core.MediaType; |
| 26 | import jakarta.ws.rs.core.Response; |
| 27 | import jakarta.ws.rs.core.Response.Status; |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 28 | |
| Michael Hanl | 704211e | 2015-06-19 07:26:04 +0200 | [diff] [blame] | 29 | /** |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 30 | * @author hanl, margaretha |
| Michael Hanl | 704211e | 2015-06-19 07:26:04 +0200 | [diff] [blame] | 31 | * @date 18/06/2015 |
| 32 | */ |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 33 | // MH todo: check position and information of rewrites! |
| margaretha | a9f5299 | 2025-06-24 11:50:15 +0200 | [diff] [blame] | 34 | public class FoundryRewriteTest extends TestBase { |
| Michael Hanl | badd79c | 2015-06-19 07:41:03 +0200 | [diff] [blame] | 35 | |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 36 | // private static String simple_add_query = "[pos=ADJA]"; |
| 37 | // private static String simple_rewrite_query = "[base=Haus]"; |
| 38 | // private static String complex_rewrite_query = "<c=INFC>"; |
| 39 | // private static String complex_rewrite_query2 = "[orth=laufe/i & base!=Lauf]"; |
| 40 | // private static String complex_rewrite_query3 = "[(base=laufen | base=gehen) & tt/pos=VVFIN]"; |
| margaretha | 5c67dd5 | 2018-12-18 17:27:05 +0100 | [diff] [blame] | 41 | @Autowired |
| 42 | public KustvaktConfiguration config; |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 43 | |
| margaretha | 5c67dd5 | 2018-12-18 17:27:05 +0100 | [diff] [blame] | 44 | @Autowired |
| margaretha | 9b754d7 | 2025-04-01 12:46:18 +0200 | [diff] [blame] | 45 | public RewriteHandler rewriteHandler; |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 46 | |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 47 | @Autowired |
| 48 | private LayerMapper m; |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 49 | |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 50 | @Test |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 51 | public void testSearchRewriteFoundryWithUserSetting () |
| 52 | throws KustvaktException { |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 53 | // create user setting |
| 54 | String json = "{\"pos-foundry\":\"opennlp\"}"; |
| 55 | String username = "foundryRewriteTest"; |
| 56 | String pathUsername = "~" + username; |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 57 | Response response = target().path(API_VERSION).path(pathUsername) |
| 58 | .path("setting").request() |
| 59 | .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler |
| 60 | .createBasicAuthorizationHeaderValue(username, "pass")) |
| 61 | .put(Entity.json(json)); |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 62 | assertEquals(Status.CREATED.getStatusCode(), response.getStatus()); |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 63 | // search |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 64 | response = target().path(API_VERSION).path("search") |
| 65 | .queryParam("q", "[pos=ADJA]").queryParam("ql", "poliqarp") |
| 66 | .request() |
| 67 | .header(Attributes.AUTHORIZATION, HttpAuthorizationHandler |
| 68 | .createBasicAuthorizationHeaderValue(username, "pass")) |
| 69 | .accept(MediaType.APPLICATION_JSON).get(); |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 70 | assertEquals(Status.OK.getStatusCode(), response.getStatus()); |
| abcpro1 | 73fe8f2 | 2022-11-08 19:56:52 +0000 | [diff] [blame] | 71 | String ent = response.readEntity(String.class); |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 72 | JsonNode node = JsonUtils.readTree(ent); |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 73 | assertEquals(node.at("/query/wrap/foundry").asText(), "opennlp"); |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 74 | assertEquals(node.at("/query/wrap/rewrites/0/scope").asText(), |
| 75 | "foundry"); |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 76 | } |
| 77 | |
| 78 | @Test |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 79 | public void testRewritePosFoundryWithUserSetting () |
| 80 | throws KustvaktException { |
| margaretha | a9f5299 | 2025-06-24 11:50:15 +0200 | [diff] [blame] | 81 | Map<String, Object> map = new HashMap<>(); |
| 82 | map.put("pos-foundry", "corenlp"); |
| 83 | map.put("lemma-foundry", "opennlp"); |
| 84 | Response response = createUpdateDefaultSettings("bubbles", map); |
| 85 | assertEquals(Status.CREATED.getStatusCode(), response.getStatus()); |
| 86 | |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 87 | String username = "bubbles"; |
| margaretha | 96c2776 | 2025-08-14 16:47:21 +0200 | [diff] [blame] | 88 | QuerySerializer s = new QuerySerializer(1.1);; |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 89 | s.setQuery("[pos=ADJA]", "poliqarp"); |
| margaretha | 9b754d7 | 2025-04-01 12:46:18 +0200 | [diff] [blame] | 90 | String result = rewriteHandler.processQuery(s.toJSON(), |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 91 | new KorAPUser(username)); |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 92 | JsonNode node = JsonUtils.readTree(result); |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 93 | assertEquals(node.at("/query/wrap/foundry").asText(), "corenlp"); |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 94 | assertEquals(node.at("/query/wrap/rewrites/0/scope").asText(), |
| 95 | "foundry"); |
| margaretha | a9f5299 | 2025-06-24 11:50:15 +0200 | [diff] [blame] | 96 | |
| 97 | testRewriteLemmaFoundryWithUserSetting(username); |
| 98 | testDeleteSetting(username); |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 99 | } |
| 100 | |
| margaretha | a9f5299 | 2025-06-24 11:50:15 +0200 | [diff] [blame] | 101 | private void testRewriteLemmaFoundryWithUserSetting (String username) |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 102 | throws KustvaktException { |
| margaretha | 96c2776 | 2025-08-14 16:47:21 +0200 | [diff] [blame] | 103 | QuerySerializer s = new QuerySerializer(1.1);; |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 104 | s.setQuery("[base=Haus]", "poliqarp"); |
| margaretha | 9b754d7 | 2025-04-01 12:46:18 +0200 | [diff] [blame] | 105 | String result = rewriteHandler.processQuery(s.toJSON(), |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 106 | new KorAPUser(username)); |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 107 | JsonNode node = JsonUtils.readTree(result); |
| 108 | // EM: only for testing, in fact, opennlp lemma does not |
| 109 | // exist! |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 110 | assertEquals(node.at("/query/wrap/foundry").asText(), "opennlp"); |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 111 | assertEquals(node.at("/query/wrap/rewrites/0/scope").asText(), |
| 112 | "foundry"); |
| margaretha | 4fa4b06 | 2019-01-28 19:43:30 +0100 | [diff] [blame] | 113 | } |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 114 | |
| Michael Hanl | badd79c | 2015-06-19 07:41:03 +0200 | [diff] [blame] | 115 | @Test |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 116 | public void testDefaultLayerMapperThrowsNoException () { |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 117 | assertEquals(config.getDefault_lemma(), m.findFoundry("lemma")); |
| 118 | assertEquals(config.getDefault_pos(), m.findFoundry("pos")); |
| margaretha | 798e8bd | 2019-02-06 15:48:58 +0100 | [diff] [blame] | 119 | assertEquals(config.getDefault_orthography(), m.findFoundry("surface")); |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 120 | assertEquals(config.getDefault_dep(), m.findFoundry("d")); |
| 121 | assertEquals(config.getDefault_const(), m.findFoundry("c")); |
| Michael Hanl | badd79c | 2015-06-19 07:41:03 +0200 | [diff] [blame] | 122 | } |
| 123 | |
| Michael Hanl | 8abaf9e | 2016-05-23 16:46:35 +0200 | [diff] [blame] | 124 | @Test |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 125 | public void testDefaultFoundryInjectLemmaThrowsNoError () |
| 126 | throws KustvaktException { |
| margaretha | 96c2776 | 2025-08-14 16:47:21 +0200 | [diff] [blame] | 127 | QuerySerializer s = new QuerySerializer(1.1);; |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 128 | s.setQuery("[base=Haus]", "poliqarp"); |
| margaretha | 9b754d7 | 2025-04-01 12:46:18 +0200 | [diff] [blame] | 129 | String result = rewriteHandler.processQuery(s.toJSON(), new KorAPUser("test")); |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 130 | JsonNode node = JsonUtils.readTree(result); |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 131 | assertNotNull(node); |
| 132 | assertFalse(node.at("/query/wrap/foundry").isMissingNode()); |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 133 | assertEquals(config.getDefault_lemma(), |
| 134 | node.at("/query/wrap/foundry").asText()); |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 135 | assertEquals(node.at("/query/wrap/layer").asText(), "lemma"); |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 136 | assertFalse(node.at("/query/wrap/rewrites").isMissingNode()); |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 137 | assertEquals(node.at("/query/wrap/rewrites/0/@type").asText(), |
| 138 | "koral:rewrite"); |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 139 | } |
| 140 | |
| Michael Hanl | 8abaf9e | 2016-05-23 16:46:35 +0200 | [diff] [blame] | 141 | @Test |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 142 | public void testDefaultFoundryInjectPOSNoErrors () |
| 143 | throws KustvaktException { |
| margaretha | 96c2776 | 2025-08-14 16:47:21 +0200 | [diff] [blame] | 144 | QuerySerializer s = new QuerySerializer(1.1);; |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 145 | s.setQuery("[pos=ADJA]", "poliqarp"); |
| margaretha | 9b754d7 | 2025-04-01 12:46:18 +0200 | [diff] [blame] | 146 | String result = rewriteHandler.processQuery(s.toJSON(), new KorAPUser("test")); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 147 | JsonNode node = JsonUtils.readTree(result); |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 148 | assertNotNull(node); |
| 149 | assertFalse(node.at("/query/wrap/foundry").isMissingNode()); |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 150 | assertEquals(config.getDefault_pos(), |
| 151 | node.at("/query/wrap/foundry").asText()); |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 152 | assertEquals(node.at("/query/wrap/layer").asText(), "pos"); |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 153 | assertFalse(node.at("/query/wrap/rewrites").isMissingNode()); |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 154 | assertEquals(node.at("/query/wrap/rewrites/0/@type").asText(), |
| 155 | "koral:rewrite"); |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 156 | } |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 157 | |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 158 | @Test |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 159 | public void testFoundryInjectJoinedQueryNoErrors () |
| 160 | throws KustvaktException { |
| margaretha | 96c2776 | 2025-08-14 16:47:21 +0200 | [diff] [blame] | 161 | QuerySerializer s = new QuerySerializer(1.1);; |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 162 | s.setQuery("[orth=laufe/i & base!=Lauf]", "poliqarp"); |
| margaretha | 9b754d7 | 2025-04-01 12:46:18 +0200 | [diff] [blame] | 163 | String result = rewriteHandler.processQuery(s.toJSON(), new KorAPUser("test")); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 164 | JsonNode node = JsonUtils.readTree(result); |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 165 | assertNotNull(node); |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 166 | assertEquals(node.at("/query/wrap/@type").asText(), "koral:termGroup"); |
| Michael Hanl | daf8660 | 2016-05-12 14:31:52 +0200 | [diff] [blame] | 167 | assertFalse(node.at("/query/wrap/operands/0/foundry").isMissingNode()); |
| 168 | assertFalse(node.at("/query/wrap/operands/0/rewrites").isMissingNode()); |
| 169 | assertFalse(node.at("/query/wrap/operands/1/foundry").isMissingNode()); |
| 170 | assertFalse(node.at("/query/wrap/operands/1/rewrites").isMissingNode()); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 171 | } |
| 172 | |
| 173 | @Test |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 174 | public void testFoundryInjectGroupedQueryNoErrors () |
| 175 | throws KustvaktException { |
| margaretha | 96c2776 | 2025-08-14 16:47:21 +0200 | [diff] [blame] | 176 | QuerySerializer s = new QuerySerializer(1.1);; |
| Michael Hanl | c0ed00f | 2016-06-23 14:33:10 +0200 | [diff] [blame] | 177 | s.setQuery("[(base=laufen | tt/pos=VVFIN)]", "poliqarp"); |
| margaretha | 9b754d7 | 2025-04-01 12:46:18 +0200 | [diff] [blame] | 178 | String result = rewriteHandler.processQuery(s.toJSON(), new KorAPUser("test")); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 179 | JsonNode node = JsonUtils.readTree(result); |
| Michael Hanl | c0ed00f | 2016-06-23 14:33:10 +0200 | [diff] [blame] | 180 | assertNotNull(node); |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 181 | assertEquals(node.at("/query/wrap/@type").asText(), "koral:termGroup"); |
| 182 | assertFalse(node.at("/query/wrap/operands/0/foundry").isMissingNode()); |
| 183 | assertFalse(node.at("/query/wrap/operands/0/rewrites").isMissingNode()); |
| Michael Hanl | c0ed00f | 2016-06-23 14:33:10 +0200 | [diff] [blame] | 184 | assertFalse(node.at("/query/wrap/operands/1/foundry").isMissingNode()); |
| 185 | assertTrue(node.at("/query/wrap/operands/1/rewrites").isMissingNode()); |
| 186 | } |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 187 | |
| Michael Hanl | c0ed00f | 2016-06-23 14:33:10 +0200 | [diff] [blame] | 188 | @Test |
| margaretha | 35e1ca2 | 2023-11-16 22:00:01 +0100 | [diff] [blame] | 189 | public void testFoundryBaseRewrite () throws KustvaktException { |
| margaretha | 96c2776 | 2025-08-14 16:47:21 +0200 | [diff] [blame] | 190 | QuerySerializer s = new QuerySerializer(1.1);; |
| Michael Hanl | c0ed00f | 2016-06-23 14:33:10 +0200 | [diff] [blame] | 191 | s.setQuery("[orth=laufen]", "poliqarp"); |
| margaretha | 9b754d7 | 2025-04-01 12:46:18 +0200 | [diff] [blame] | 192 | String result = rewriteHandler.processQuery(s.toJSON(), new KorAPUser("test")); |
| Michael Hanl | c0ed00f | 2016-06-23 14:33:10 +0200 | [diff] [blame] | 193 | JsonNode node = JsonUtils.readTree(result); |
| Marc Kupietz | d43a98d | 2023-09-22 17:11:46 +0200 | [diff] [blame] | 194 | assertEquals(node.at("/query/wrap/@type").asText(), "koral:term"); |
| 195 | assertFalse(node.at("/query/wrap/foundry").isMissingNode()); |
| 196 | assertFalse(node.at("/query/wrap/rewrites").isMissingNode()); |
| Michael Hanl | 1e18cb4 | 2015-08-06 20:57:35 +0200 | [diff] [blame] | 197 | } |
| Michael Hanl | 704211e | 2015-06-19 07:26:04 +0200 | [diff] [blame] | 198 | } |