Smalyshev has uploaded a new change for review.
https://gerrit.wikimedia.org/r/264854
Change subject: Add support for wktLiteral parsing
......................................................................
Add support for wktLiteral parsing
Bug: T123612
Change-Id: I9931a584c5aaa7a8cd22e31c94eca2cff5baae15
---
M blazegraph/pom.xml
M
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/WikibaseExtensionFactory.java
M
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/WikibaseVocabulary.java
A
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/literal/WikibaseGeoExtension.java
M
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/uri/ValuePropertiesInlineUriHandler.java
M
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/uri/WikibaseStyleStatementInlineUriHandler.java
A
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/vocabulary/GeoSparqlVocabularyDecl.java
M
blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/vocabulary/ProvenanceVocabularyDecl.java
A
blazegraph/src/test/java/org/wikidata/query/rdf/blazegraph/WikibaseGeoUnitTest.java
A common/src/main/java/org/wikidata/query/rdf/common/uri/GeoSparql.java
M dist/src/script/RWStore.properties
M tools/pom.xml
M tools/src/test/resources/blazegraph/RWStore.properties
M war/pom.xml
M war/src/assembly/dist.xml
15 files changed, 255 insertions(+), 10 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/wikidata/query/rdf
refs/changes/54/264854/1
diff --git a/blazegraph/pom.xml b/blazegraph/pom.xml
index 24272e7..7cf053c 100644
--- a/blazegraph/pom.xml
+++ b/blazegraph/pom.xml
@@ -41,6 +41,11 @@
<version>${project.parent.version}</version>
<scope>test</scope>
</dependency>
+ <dependency>
+ <groupId>com.esri.geometry</groupId>
+ <artifactId>esri-geometry-api</artifactId>
+ <version>1.2.1</version>
+ </dependency>
</dependencies>
<build>
diff --git
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/WikibaseExtensionFactory.java
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/WikibaseExtensionFactory.java
index 41ce5c3..87976a4 100644
---
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/WikibaseExtensionFactory.java
+++
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/WikibaseExtensionFactory.java
@@ -3,9 +3,11 @@
import java.util.Collection;
import java.util.Iterator;
-//import org.slf4j.Logger;
-//import org.slf4j.LoggerFactory;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.wikidata.query.rdf.blazegraph.inline.literal.WikibaseDateExtension;
+import org.wikidata.query.rdf.blazegraph.inline.literal.WikibaseGeoExtension;
import com.bigdata.rdf.internal.DefaultExtensionFactory;
import com.bigdata.rdf.internal.IDatatypeURIResolver;
@@ -19,7 +21,7 @@
* Setup inline value extensions to Blazegraph for Wikidata.
*/
public class WikibaseExtensionFactory extends DefaultExtensionFactory {
- // private static final Logger log =
LoggerFactory.getLogger(WikibaseExtensionFactory.class);
+ private static final Logger log =
LoggerFactory.getLogger(WikibaseExtensionFactory.class);
@Override
@SuppressWarnings("rawtypes")
@@ -33,7 +35,8 @@
}
}
extensions.add(new
WikibaseDateExtension<BigdataLiteral>(resolver));
- // log.warn("Installed Wikidata date extensions");
}
+ extensions.add(new WikibaseGeoExtension<BigdataLiteral>(resolver));
+ // log.warn("Installed Wikidata date extensions");
}
}
diff --git
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/WikibaseVocabulary.java
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/WikibaseVocabulary.java
index 6ab30cc..4c89fae 100644
---
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/WikibaseVocabulary.java
+++
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/WikibaseVocabulary.java
@@ -1,6 +1,7 @@
package org.wikidata.query.rdf.blazegraph;
import org.wikidata.query.rdf.blazegraph.vocabulary.CommonValuesVocabularyDecl;
+import org.wikidata.query.rdf.blazegraph.vocabulary.GeoSparqlVocabularyDecl;
import org.wikidata.query.rdf.blazegraph.vocabulary.OntologyVocabularyDecl;
import org.wikidata.query.rdf.blazegraph.vocabulary.ProvenanceVocabularyDecl;
import org.wikidata.query.rdf.blazegraph.vocabulary.SchemaDotOrgVocabularyDecl;
@@ -19,7 +20,7 @@
/**
* Current vocabulary class.
*/
- public static final Class VOCABULARY_CLASS = V001.class;
+ public static final Class VOCABULARY_CLASS = V002.class;
protected WikibaseVocabulary() {
// prevents calls from subclass
@@ -76,6 +77,7 @@
addDecl(new SchemaDotOrgVocabularyDecl());
addDecl(new ProvenanceVocabularyDecl());
addDecl(new CommonValuesVocabularyDecl());
+ addDecl(new GeoSparqlVocabularyDecl());
super.addValues();
}
}
diff --git
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/literal/WikibaseGeoExtension.java
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/literal/WikibaseGeoExtension.java
new file mode 100644
index 0000000..dd5572b
--- /dev/null
+++
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/literal/WikibaseGeoExtension.java
@@ -0,0 +1,150 @@
+package org.wikidata.query.rdf.blazegraph.inline.literal;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.Locale;
+import java.util.Set;
+
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.model.impl.URIImpl;
+
+import static org.wikidata.query.rdf.common.uri.GeoSparql.WKT_LITERAL;
+
+import com.bigdata.rdf.internal.IDatatypeURIResolver;
+import com.bigdata.rdf.internal.impl.extensions.GeoSpatialLiteralExtension;
+import
com.bigdata.rdf.internal.impl.extensions.GeoSpatialLiteralExtension.SchemaFieldDescription.Datatype;
+import com.bigdata.rdf.internal.impl.literal.LiteralExtensionIV;
+import com.bigdata.rdf.model.BigdataURI;
+import com.bigdata.rdf.model.BigdataValue;
+import com.bigdata.rdf.model.BigdataValueFactory;
+import com.esri.core.geometry.OperatorImportFromWkt;
+import com.esri.core.geometry.Point;
+import com.esri.core.geometry.Geometry;
+import com.esri.core.geometry.WktImportFlags;
+
+/**
+ * Wikibase extension for geographic coordinate type.
+ * See also: GeoSpatialLiteralExtension
+ * @param <V> Blazegraph value to expand. These are usually treated a bit
+ * roughly by Blazegraph - lots of rawtypes
+ */
+public class WikibaseGeoExtension<V extends BigdataValue> extends
GeoSpatialLiteralExtension<V> {
+
+ /**
+ * Datatype URI for geo coordinate.
+ * It's geo:wktLiteral
+ */
+ private final URI datatypeURI = new URIImpl(WKT_LITERAL);
+
+ /**
+ * Resolved datatype for the geo literal.
+ */
+ private final BigdataURI datatype;
+
+ /**
+ * Literal precision.
+ */
+ private static final long PRECISION = 1000000000L;
+ /**
+ * Format for printing WKT literals.
+ */
+ private static final String DECIMAL_FORMAT = "POINT(%.9f %.9f)";
+
+ public WikibaseGeoExtension(final IDatatypeURIResolver resolver) {
+ super(resolver, getGeoSchema());
+ this.datatype = resolver.resolve(datatypeURI);
+ }
+
+ /**
+ * Get the schema for our geo data.
+ * @return
+ */
+ private static SchemaDescription getGeoSchema() {
+ final SchemaFieldDescription coord = new
SchemaFieldDescription(Datatype.DOUBLE, PRECISION);
+ final SchemaFieldDescription[] schema = new SchemaFieldDescription[]
{coord, coord};
+ return new SchemaDescription(Arrays.asList(schema));
+ }
+
+ @Override
+ public Set<BigdataURI> getDatatypes() {
+ final HashSet<BigdataURI> datatypes = new LinkedHashSet<BigdataURI>();
+ datatypes.add(datatype);
+ return datatypes;
+ }
+
+ /**
+ * Parse WKT string into two doubles.
+ * @param value
+ * @return
+ */
+ private Object[] parseWKT(String value) {
+ Point geom =
(Point)OperatorImportFromWkt.local().execute(WktImportFlags.wktImportDefaults,
+ Geometry.Type.Point, value, null);
+
+ // parse WKT literal and return components
+ return new Object[] {geom.getX(), geom.getY()};
+ }
+
+ @Override
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public LiteralExtensionIV createIV(Value value) {
+ final Object[] wktItems = parseWKT(value.stringValue());
+ final LiteralExtensionIV iv = createIV(wktItems);
+ return new LiteralExtensionIV(iv.getDelegate(), datatype.getIV());
+ }
+
+ /**
+ * Print coordinates as WKT literal.
+ * @param x
+ * @param y
+ * @return
+ */
+ private String printAsWKT(double x, double y) {
+ return String.format(Locale.ROOT, DECIMAL_FORMAT, x, y);
+ }
+
+ @Override
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ public V asValue(LiteralExtensionIV iv, BigdataValueFactory vf) {
+ // get the components represented by the IV (which must be of type
+ // xsd:integer (G->C)
+ final Object[] components = longArrAsComponentArr(asLongArray(iv));
+
+ // set up the component and merge them into a string (C->B)
+ final String litStr = printAsWKT((double)components[0],
(double)components[1]);
+
+ // setup a literal carrying the component string (B->A)
+ return (V) vf.createLiteral(litStr, datatype);
+ }
+
+ /**
+ * Decodes an xsd:integer into the long values of the z-order components
+ * represented through the xsd:integer.
+ *
+ * Implements transformation G->C
+ * FIXME: this duplicates the parent one because of datatype override.
+ * Better solution would be to make it protected.
+ * @param iv
+ * @return
+ */
+ @Override
+ @SuppressWarnings("rawtypes")
+ public long[] asLongArray(final LiteralExtensionIV iv) {
+ if (!datatype.getIV().equals(iv.getExtensionIV())) {
+ throw new IllegalArgumentException("unrecognized datatype");
+ }
+
+ final BigInteger bigInt = iv.getDelegate().integerValue();
+
+ // big integer to zOrder byte[] (F>D2)
+ final byte[] bigIntAsByteArrUnsigned = toZOrderByteArray(bigInt);
+
+ // retrieve the original long values from z-order byte[] (D2 -> C)
+ final long[] componentsAsLongArr =
fromZOrderByteArray(bigIntAsByteArrUnsigned);
+
+ return componentsAsLongArr;
+ }
+}
diff --git
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/uri/ValuePropertiesInlineUriHandler.java
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/uri/ValuePropertiesInlineUriHandler.java
index aa54cc7..d7f7a8e 100644
---
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/uri/ValuePropertiesInlineUriHandler.java
+++
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/uri/ValuePropertiesInlineUriHandler.java
@@ -11,6 +11,7 @@
* InlineURIHandler for value and qualifier properties. Can't just use
* InlineUnsignedIntegerURIHandler because values can end in -value. Those we
* represent as negative numbers.
+ * @deprecated
*/
public class ValuePropertiesInlineUriHandler extends InlineURIHandler {
/**
diff --git
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/uri/WikibaseStyleStatementInlineUriHandler.java
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/uri/WikibaseStyleStatementInlineUriHandler.java
index 52f3010..1c158a4 100644
---
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/uri/WikibaseStyleStatementInlineUriHandler.java
+++
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/inline/uri/WikibaseStyleStatementInlineUriHandler.java
@@ -26,6 +26,7 @@
* statements to get scattered along the index which causes mighty right
* amplification during loads and updates and probably doesn't help query
* performance either.
+ * @deprecated
*/
public class WikibaseStyleStatementInlineUriHandler extends InlineURIHandler {
private static final Logger log =
Logger.getLogger(WikibaseStyleStatementInlineUriHandler.class);
diff --git
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/vocabulary/GeoSparqlVocabularyDecl.java
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/vocabulary/GeoSparqlVocabularyDecl.java
new file mode 100644
index 0000000..8a76852
--- /dev/null
+++
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/vocabulary/GeoSparqlVocabularyDecl.java
@@ -0,0 +1,17 @@
+package org.wikidata.query.rdf.blazegraph.vocabulary;
+
+import com.bigdata.rdf.vocab.BaseVocabularyDecl;
+import static org.wikidata.query.rdf.common.uri.GeoSparql.NAMESPACE;
+import static org.wikidata.query.rdf.common.uri.GeoSparql.WKT_LITERAL;
+
+
+/**
+ * Vocabulary containing the URIs from
+ * {@linkplain org.wikidata.query.rdf.common.uri.GeoSparql} that are imported
+ * into Blazegraph.
+ */
+public class GeoSparqlVocabularyDecl extends BaseVocabularyDecl {
+ public GeoSparqlVocabularyDecl() {
+ super(NAMESPACE, WKT_LITERAL);
+ }
+}
diff --git
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/vocabulary/ProvenanceVocabularyDecl.java
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/vocabulary/ProvenanceVocabularyDecl.java
index 7379334..2ffa987 100644
---
a/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/vocabulary/ProvenanceVocabularyDecl.java
+++
b/blazegraph/src/main/java/org/wikidata/query/rdf/blazegraph/vocabulary/ProvenanceVocabularyDecl.java
@@ -8,7 +8,7 @@
/**
* Vocabulary containing the URIs from
- * {@linkplain org.wikidata.query.rdf.common.uri.Ontology} that are imported
+ * {@linkplain org.wikidata.query.rdf.common.uri.Provenance} that are imported
* into Blazegraph.
*/
public class ProvenanceVocabularyDecl extends BaseVocabularyDecl {
diff --git
a/blazegraph/src/test/java/org/wikidata/query/rdf/blazegraph/WikibaseGeoUnitTest.java
b/blazegraph/src/test/java/org/wikidata/query/rdf/blazegraph/WikibaseGeoUnitTest.java
new file mode 100644
index 0000000..b26e369
--- /dev/null
+++
b/blazegraph/src/test/java/org/wikidata/query/rdf/blazegraph/WikibaseGeoUnitTest.java
@@ -0,0 +1,24 @@
+package org.wikidata.query.rdf.blazegraph;
+
+import static org.hamcrest.Matchers.instanceOf;
+
+import org.junit.Test;
+import org.openrdf.model.impl.LiteralImpl;
+import org.openrdf.model.impl.URIImpl;
+import org.wikidata.query.rdf.common.uri.GeoSparql;
+import org.wikidata.query.rdf.common.uri.Ontology;
+
+import com.bigdata.rdf.internal.impl.literal.LiteralExtensionIV;
+import com.bigdata.rdf.model.BigdataStatement;
+
+public class WikibaseGeoUnitTest extends AbstractRandomizedBlazegraphTestBase {
+
+ @Test
+ public void geoExtension() {
+ BigdataStatement statement = roundTrip(Ontology.Geo.GLOBE,
Ontology.Geo.LATITUDE,
+ new LiteralImpl("Point(1.2 3.4)", new
URIImpl(GeoSparql.WKT_LITERAL)));
+ assertThat(statement.getObject().getIV(),
instanceOf(LiteralExtensionIV.class));
+ assertEquals(statement.getObject().toString(), "\"POINT(1.200000000
3.400000000)\"^^<"+GeoSparql.WKT_LITERAL+">");
+ }
+
+}
diff --git
a/common/src/main/java/org/wikidata/query/rdf/common/uri/GeoSparql.java
b/common/src/main/java/org/wikidata/query/rdf/common/uri/GeoSparql.java
new file mode 100644
index 0000000..02c58f1
--- /dev/null
+++ b/common/src/main/java/org/wikidata/query/rdf/common/uri/GeoSparql.java
@@ -0,0 +1,20 @@
+package org.wikidata.query.rdf.common.uri;
+
+/**
+ * GeoSPARQL URIs.
+ */
+public final class GeoSparql {
+ /**
+ * geo: namespace.
+ */
+ public static final String NAMESPACE =
"http://www.opengis.net/ont/geosparql#";
+
+ /**
+ * WKT literal type.
+ */
+ public static final String WKT_LITERAL = NAMESPACE + "wktLiteral";
+
+ private GeoSparql() {
+ // Utility uncallable constructor
+ }
+}
diff --git a/dist/src/script/RWStore.properties
b/dist/src/script/RWStore.properties
index 399e21f..f9034e1 100644
--- a/dist/src/script/RWStore.properties
+++ b/dist/src/script/RWStore.properties
@@ -14,7 +14,7 @@
com.bigdata.rdf.store.AbstractTripleStore.axiomsClass=com.bigdata.rdf.axioms.NoAxioms
# Use our private vocabularies
-com.bigdata.rdf.store.AbstractTripleStore.vocabularyClass=org.wikidata.query.rdf.blazegraph.WikibaseVocabulary$V001
+com.bigdata.rdf.store.AbstractTripleStore.vocabularyClass=org.wikidata.query.rdf.blazegraph.WikibaseVocabulary$V002
com.bigdata.rdf.store.AbstractTripleStore.inlineURIFactory=org.wikidata.query.rdf.blazegraph.WikibaseInlineUriFactory
com.bigdata.rdf.store.AbstractTripleStore.extensionFactoryClass=org.wikidata.query.rdf.blazegraph.WikibaseExtensionFactory
@@ -41,3 +41,5 @@
# See https://jira.blazegraph.com/browse/BLZG-1385 - reduce LRU cache timeout
com.bigdata.journal.AbstractJournal.historicalIndexCacheCapacity=20
com.bigdata.journal.AbstractJournal.historicalIndexCacheTimeout=5
+# Geospatial ON
+com.bigdata.rdf.store.AbstractTripleStore.geoSpatial=true
\ No newline at end of file
diff --git a/tools/pom.xml b/tools/pom.xml
index 4740435..6c87f6a 100644
--- a/tools/pom.xml
+++ b/tools/pom.xml
@@ -160,6 +160,11 @@
<artifactId>blazegraph</artifactId>
<version>${project.parent.version}</version>
</artifactItem>
+ <artifactItem>
+ <groupId>com.esri.geometry</groupId>
+ <artifactId>esri-geometry-api</artifactId>
+ <version>1.2.1</version>
+ </artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}/blazegraph/WEB-INF/lib</outputDirectory>
</configuration>
@@ -180,13 +185,13 @@
<configuration>
<properties>
<property>
- <!-- By default Blazegraph's WAR thinks it running in tomcat
and uses funky relative paths. They suggest
+ <!-- By default Blazegraph's WAR thinks it running in tomcat
and uses funky relative paths. They suggest
you overwrite it. We do. -->
<name>com.bigdata.rdf.sail.webapp.ConfigParams.propertyFile</name>
<value>${project.basedir}/src/test/resources/blazegraph/RWStore.properties</value>
</property>
<property>
- <!-- 100x more than the default form size limit - our
updates are reasonably large and it isn't worth breaking
+ <!-- 100x more than the default form size limit - our
updates are reasonably large and it isn't worth breaking
them up. Hopefully. -->
<name>org.eclipse.jetty.server.Request.maxFormContentSize</name>
<value>20000000</value>
diff --git a/tools/src/test/resources/blazegraph/RWStore.properties
b/tools/src/test/resources/blazegraph/RWStore.properties
index 6088420..9a4efed 100644
--- a/tools/src/test/resources/blazegraph/RWStore.properties
+++ b/tools/src/test/resources/blazegraph/RWStore.properties
@@ -23,10 +23,12 @@
com.bigdata.rdf.store.AbstractTripleStore.axiomsClass=com.bigdata.rdf.axioms.NoAxioms
# Use the default vocabulary for now.
-com.bigdata.rdf.store.AbstractTripleStore.vocabularyClass=org.wikidata.query.rdf.blazegraph.WikibaseVocabulary$V001
+com.bigdata.rdf.store.AbstractTripleStore.vocabularyClass=org.wikidata.query.rdf.blazegraph.WikibaseVocabulary$V002
com.bigdata.rdf.store.AbstractTripleStore.inlineURIFactory=org.wikidata.query.rdf.blazegraph.WikibaseInlineUriFactory
com.bigdata.rdf.store.AbstractTripleStore.extensionFactoryClass=org.wikidata.query.rdf.blazegraph.WikibaseExtensionFactory
# These seem to be ubiquitous overwrites. Not sure why they aren't the
default but it works.
com.bigdata.namespace.kb.lex.com.bigdata.btree.BTree.branchingFactor=400
com.bigdata.namespace.kb.spo.com.bigdata.btree.BTree.branchingFactor=1024
+# Geospatial ON
+com.bigdata.rdf.store.AbstractTripleStore.geoSpatial=true
\ No newline at end of file
diff --git a/war/pom.xml b/war/pom.xml
index e254075..d21a0fa 100644
--- a/war/pom.xml
+++ b/war/pom.xml
@@ -35,6 +35,11 @@
<artifactId>blazegraph</artifactId>
<version>${project.parent.version}</version>
</dependency>
+ <dependency>
+ <groupId>com.esri.geometry</groupId>
+ <artifactId>esri-geometry-api</artifactId>
+ <version>1.2.1</version>
+ </dependency>
</dependencies>
<build>
diff --git a/war/src/assembly/dist.xml b/war/src/assembly/dist.xml
index 50a7288..0db1289 100644
--- a/war/src/assembly/dist.xml
+++ b/war/src/assembly/dist.xml
@@ -40,6 +40,14 @@
<dependencySet>
<outputDirectory>WEB-INF/lib</outputDirectory>
<includes>
+ <include>com.esri.geometry:esri-geometry-api:jar</include>
+ </includes>
+ <useProjectArtifact>false</useProjectArtifact>
+ </dependencySet>
+
+ <dependencySet>
+ <outputDirectory>WEB-INF/lib</outputDirectory>
+ <includes>
<include>${project.groupId}:*:jar</include>
</includes>
<useProjectArtifact>false</useProjectArtifact>
--
To view, visit https://gerrit.wikimedia.org/r/264854
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9931a584c5aaa7a8cd22e31c94eca2cff5baae15
Gerrit-PatchSet: 1
Gerrit-Project: wikidata/query/rdf
Gerrit-Branch: master
Gerrit-Owner: Smalyshev <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits