From 13156dd29c9f42dd17733280ba4f03f305345c2b Mon Sep 17 00:00:00 2001 From: Colin Goodheart-Smithe Date: Mon, 4 Jun 2018 09:17:11 +0100 Subject: [PATCH 01/21] [DOCS] Rewords _field_names documentation (#31029) * [DOCS] Rewords _field_names documentation Corrects the language around when we write to `_field_names` and when you might want to disable it given that n recent versions it does not carry the indexing overhead it once did. Relates to #30862 * Update wording following review --- .../mapping/fields/field-names-field.asciidoc | 46 +++++-------------- 1 file changed, 11 insertions(+), 35 deletions(-) diff --git a/docs/reference/mapping/fields/field-names-field.asciidoc b/docs/reference/mapping/fields/field-names-field.asciidoc index 2539bf4287abe..6cba81b54f1ba 100644 --- a/docs/reference/mapping/fields/field-names-field.asciidoc +++ b/docs/reference/mapping/fields/field-names-field.asciidoc @@ -1,47 +1,23 @@ [[mapping-field-names-field]] === `_field_names` field -The `_field_names` field indexes the names of every field in a document that -contains any value other than `null`. This field is used by the +The `_field_names` field used to index the names of every field in a document that +contains any value other than `null`. This field was used by the <> query to find documents that either have or don't have any non-+null+ value for a particular field. -The value of the `_field_names` field is accessible in queries: - -[source,js] --------------------------- -# Example documents -PUT my_index/_doc/1 -{ - "title": "This is a document" -} - -PUT my_index/_doc/2?refresh=true -{ - "title": "This is another document", - "body": "This document has a body" -} - -GET my_index/_search -{ - "query": { - "terms": { - "_field_names": [ "title" ] <1> - } - } -} - --------------------------- -// CONSOLE - -<1> Querying on the `_field_names` field (also see the <> query) - +Now the `_field_names` field only indexes the names of fields that have +`doc_values` and `norms` disabled. For fields which have either `doc_values` +or `norm` enabled the <> query will still +be available but will not use the `_field_names` field. ==== Disabling `_field_names` -Because `_field_names` introduce some index-time overhead, you might want to -disable this field if you want to optimize for indexing speed and do not need -`exists` queries. +Disabling `_field_names` is often not necessary because it no longer +carries the index overhead it once did. If you have a lot of fields +which have `doc_values` and `norms` disabled and you do not need to +execute `exists` queries using those fields you might want to disable +`_field_names` be adding the following to the mappings: [source,js] -------------------------------------------------- From 673bdf2842575c58f660e467771f2444fd2ea464 Mon Sep 17 00:00:00 2001 From: Colin Goodheart-Smithe Date: Mon, 4 Jun 2018 09:19:38 +0100 Subject: [PATCH 02/21] [DOCS] Fixes accounting setting names (#30863) The documentation for the account circuit breaker listed the settings for it's limit and overhead to be `network.breaker.accounting.limit` and `network.breaker.accounting.overhead` when in `HieratchyCircuitBreakerService` it seems the settings are actually `indices.breaker.accounting.limit` and `indices.breaker.accounting.overhead`. --- docs/reference/modules/indices/circuit_breaker.asciidoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/reference/modules/indices/circuit_breaker.asciidoc b/docs/reference/modules/indices/circuit_breaker.asciidoc index 3df187086bb69..03cdb307b9f1e 100644 --- a/docs/reference/modules/indices/circuit_breaker.asciidoc +++ b/docs/reference/modules/indices/circuit_breaker.asciidoc @@ -80,12 +80,12 @@ The accounting circuit breaker allows Elasticsearch to limit the memory usage of things held in memory that are not released when a request is completed. This includes things like the Lucene segment memory. -`network.breaker.accounting.limit`:: +`indices.breaker.accounting.limit`:: Limit for accounting breaker, defaults to 100% of JVM heap. This means that it is bound by the limit configured for the parent circuit breaker. -`network.breaker.accounting.overhead`:: +`indices.breaker.accounting.overhead`:: A constant that all accounting estimations are multiplied with to determine a final estimation. Defaults to 1 From 8f4711f3f6fc6a5a190951de4df173eeee015918 Mon Sep 17 00:00:00 2001 From: Alan Woodward Date: Mon, 4 Jun 2018 08:50:35 +0100 Subject: [PATCH 03/21] Index phrases (#30450) Specifying `index_phrases: true` on a text field mapping will add a subsidiary [field]._index_phrase field, indexing two-term shingles from the parent field. The parent analysis chain is re-used, wrapped with a FixedShingleFilter. At query time, if a phrase match query is executed, the mapping will redirect it to run against the subsidiary field. This should trade faster phrase querying for a larger index and longer indexing times. Relates to #27049 --- docs/reference/mapping/types/text.asciidoc | 8 + .../test/search/200_index_phrase_search.yml | 67 +++++ .../index/mapper/MappedFieldType.java | 10 + .../index/mapper/TextFieldMapper.java | 234 +++++++++++++++++- .../index/query/MatchPhraseQueryBuilder.java | 1 + .../index/search/MatchQuery.java | 31 ++- .../index/mapper/TextFieldMapperTests.java | 112 ++++++++- .../index/mapper/TextFieldTypeTests.java | 7 + 8 files changed, 456 insertions(+), 14 deletions(-) create mode 100644 rest-api-spec/src/main/resources/rest-api-spec/test/search/200_index_phrase_search.yml diff --git a/docs/reference/mapping/types/text.asciidoc b/docs/reference/mapping/types/text.asciidoc index 988a2ada38d7e..fd5bb312ef15c 100644 --- a/docs/reference/mapping/types/text.asciidoc +++ b/docs/reference/mapping/types/text.asciidoc @@ -96,6 +96,14 @@ The following parameters are accepted by `text` fields: the expense of a larger index. Accepts an <> +<>:: + + If enabled, two-term word combinations ('shingles') are indexed into a separate + field. This allows exact phrase queries to run more efficiently, at the expense + of a larger index. Note that this works best when stopwords are not removed, + as phrases containing stopwords will not use the subsidiary field and will fall + back to a standard phrase query. Accepts `true` or `false` (default). + <>:: Whether field-length should be taken into account when scoring queries. diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search/200_index_phrase_search.yml b/rest-api-spec/src/main/resources/rest-api-spec/test/search/200_index_phrase_search.yml new file mode 100644 index 0000000000000..241fbc187dec6 --- /dev/null +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search/200_index_phrase_search.yml @@ -0,0 +1,67 @@ +--- +"search with indexed phrases": + - skip: + version: " - 6.99.99" + reason: index_phrase is only available as of 7.0.0 + - do: + indices.create: + index: test + body: + mappings: + test: + properties: + text: + type: text + index_phrases: true + + - do: + index: + index: test + type: test + id: 1 + body: { text: "peter piper picked a peck of pickled peppers" } + + - do: + indices.refresh: + index: [test] + + - do: + search: + index: test + body: + query: + match_phrase: + text: + query: "peter piper" + + - match: {hits.total: 1} + + - do: + search: + index: test + q: '"peter piper"~1' + df: text + + - match: {hits.total: 1} + + - do: + search: + index: test + body: + query: + match_phrase: + text: "peter piper picked" + + - match: {hits.total: 1} + + - do: + search: + index: test + body: + query: + match_phrase: + text: "piper" + + - match: {hits.total: 1} + + diff --git a/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java b/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java index 708be4c3f2328..f4120bea5372a 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/MappedFieldType.java @@ -19,6 +19,7 @@ package org.elasticsearch.index.mapper; +import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.document.FieldType; import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.IndexReader; @@ -44,6 +45,7 @@ import org.elasticsearch.index.query.QueryRewriteContext; import org.elasticsearch.index.query.QueryShardContext; import org.elasticsearch.index.query.QueryShardException; +import org.elasticsearch.index.search.MatchQuery; import org.elasticsearch.index.similarity.SimilarityProvider; import org.elasticsearch.search.DocValueFormat; import org.joda.time.DateTimeZone; @@ -382,6 +384,14 @@ public Query nullValueQuery() { public abstract Query existsQuery(QueryShardContext context); + public Query phraseQuery(String field, TokenStream stream, int slop, boolean enablePositionIncrements) throws IOException { + throw new IllegalArgumentException("Can only use phrase queries on text fields - not on [" + name + "] which is of type [" + typeName() + "]"); + } + + public Query multiPhraseQuery(String field, TokenStream stream, int slop, boolean enablePositionIncrements) throws IOException { + throw new IllegalArgumentException("Can only use phrase queries on text fields - not on [" + name + "] which is of type [" + typeName() + "]"); + } + /** * An enum used to describe the relation between the range of terms in a * shard when compared with a query range diff --git a/server/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java index 7d0aa155a3f43..110b7cf90123e 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/TextFieldMapper.java @@ -19,21 +19,30 @@ package org.elasticsearch.index.mapper; +import org.apache.logging.log4j.Logger; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.AnalyzerWrapper; +import org.apache.lucene.analysis.CachingTokenFilter; import org.apache.lucene.analysis.TokenFilter; +import org.apache.lucene.analysis.TokenStream; import org.apache.lucene.analysis.ngram.EdgeNGramTokenFilter; +import org.apache.lucene.analysis.shingle.FixedShingleFilter; +import org.apache.lucene.analysis.tokenattributes.PositionIncrementAttribute; +import org.apache.lucene.analysis.tokenattributes.TermToBytesRefAttribute; import org.apache.lucene.document.Field; import org.apache.lucene.document.FieldType; import org.apache.lucene.index.IndexOptions; import org.apache.lucene.index.IndexableField; import org.apache.lucene.index.Term; import org.apache.lucene.search.ConstantScoreQuery; +import org.apache.lucene.search.MultiPhraseQuery; import org.apache.lucene.search.MultiTermQuery; import org.apache.lucene.search.NormsFieldExistsQuery; +import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; import org.elasticsearch.common.collect.Iterators; +import org.elasticsearch.common.logging.ESLoggerFactory; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.support.XContentMapValues; @@ -44,7 +53,7 @@ import org.elasticsearch.index.query.QueryShardContext; import java.io.IOException; -import java.util.Collections; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -55,9 +64,13 @@ /** A {@link FieldMapper} for full-text fields. */ public class TextFieldMapper extends FieldMapper { + private static final Logger logger = ESLoggerFactory.getLogger(TextFieldMapper.class); + public static final String CONTENT_TYPE = "text"; private static final int POSITION_INCREMENT_GAP_USE_ANALYZER = -1; + public static final String FAST_PHRASE_SUFFIX = "._index_phrase"; + public static class Defaults { public static final double FIELDDATA_MIN_FREQUENCY = 0; public static final double FIELDDATA_MAX_FREQUENCY = Integer.MAX_VALUE; @@ -106,6 +119,11 @@ public Builder fielddata(boolean fielddata) { return builder; } + public Builder indexPhrases(boolean indexPhrases) { + fieldType().setIndexPhrases(indexPhrases); + return builder; + } + @Override public Builder docValues(boolean docValues) { if (docValues) { @@ -167,8 +185,16 @@ public TextFieldMapper build(BuilderContext context) { prefixFieldType.setAnalyzer(fieldType.indexAnalyzer()); prefixMapper = new PrefixFieldMapper(prefixFieldType, context.indexSettings()); } + if (fieldType().indexPhrases) { + if (fieldType().isSearchable() == false) { + throw new IllegalArgumentException("Cannot set index_phrases on unindexed field [" + name() + "]"); + } + if (fieldType.indexOptions().compareTo(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS) < 0) { + throw new IllegalArgumentException("Cannot set index_phrases on field [" + name() + "] if positions are not enabled"); + } + } return new TextFieldMapper( - name, fieldType, defaultFieldType, positionIncrementGap, includeInAll, prefixMapper, + name, fieldType(), defaultFieldType, positionIncrementGap, includeInAll, prefixMapper, context.indexSettings(), multiFieldsBuilder.build(this, context), copyTo); } } @@ -212,12 +238,35 @@ public Mapper.Builder parse(String fieldName, Map node, ParserCo builder.indexPrefixes(minChars, maxChars); DocumentMapperParser.checkNoRemainingFields(propName, indexPrefix, parserContext.indexVersionCreated()); iterator.remove(); + } else if (propName.equals("index_phrases")) { + builder.indexPhrases(XContentMapValues.nodeBooleanValue(propNode, "index_phrases")); + iterator.remove(); } } return builder; } } + private static class PhraseWrappedAnalyzer extends AnalyzerWrapper { + + private final Analyzer delegate; + + PhraseWrappedAnalyzer(Analyzer delegate) { + super(delegate.getReuseStrategy()); + this.delegate = delegate; + } + + @Override + protected Analyzer getWrappedAnalyzer(String fieldName) { + return delegate; + } + + @Override + protected TokenStreamComponents wrapComponents(String fieldName, TokenStreamComponents components) { + return new TokenStreamComponents(components.getTokenizer(), new FixedShingleFilter(components.getTokenStream(), 2)); + } + } + private static class PrefixWrappedAnalyzer extends AnalyzerWrapper { private final int minChars; @@ -243,6 +292,46 @@ protected TokenStreamComponents wrapComponents(String fieldName, TokenStreamComp } } + private static final class PhraseFieldType extends StringFieldType { + + final TextFieldType parent; + + PhraseFieldType(TextFieldType parent) { + setTokenized(true); + setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS); + if (parent.indexOptions() == IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS) { + setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS); + } + if (parent.storeTermVectorOffsets()) { + setStoreTermVectors(true); + setStoreTermVectorPositions(true); + setStoreTermVectorOffsets(true); + } + setAnalyzer(parent.indexAnalyzer().name(), parent.indexAnalyzer().analyzer()); + setName(parent.name() + FAST_PHRASE_SUFFIX); + this.parent = parent; + } + + void setAnalyzer(String name, Analyzer delegate) { + setIndexAnalyzer(new NamedAnalyzer(name, AnalyzerScope.INDEX, new PhraseWrappedAnalyzer(delegate))); + } + + @Override + public MappedFieldType clone() { + return new PhraseFieldType(parent); + } + + @Override + public String typeName() { + return "phrase"; + } + + @Override + public Query existsQuery(QueryShardContext context) { + throw new UnsupportedOperationException(); + } + } + static final class PrefixFieldType extends StringFieldType { final int minChars; @@ -311,6 +400,23 @@ public int hashCode() { } } + private static final class PhraseFieldMapper extends FieldMapper { + + PhraseFieldMapper(PhraseFieldType fieldType, Settings indexSettings) { + super(fieldType.name(), fieldType, fieldType, indexSettings, MultiFields.empty(), CopyTo.empty()); + } + + @Override + protected void parseCreateField(ParseContext context, List fields) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + protected String contentType() { + return "phrase"; + } + } + private static final class PrefixFieldMapper extends FieldMapper { protected PrefixFieldMapper(PrefixFieldType fieldType, Settings indexSettings) { @@ -344,6 +450,7 @@ public static final class TextFieldType extends StringFieldType { private double fielddataMaxFrequency; private int fielddataMinSegmentSize; private PrefixFieldType prefixFieldType; + private boolean indexPhrases = false; public TextFieldType() { setTokenized(true); @@ -359,6 +466,7 @@ protected TextFieldType(TextFieldType ref) { this.fielddataMinFrequency = ref.fielddataMinFrequency; this.fielddataMaxFrequency = ref.fielddataMaxFrequency; this.fielddataMinSegmentSize = ref.fielddataMinSegmentSize; + this.indexPhrases = ref.indexPhrases; if (ref.prefixFieldType != null) { this.prefixFieldType = ref.prefixFieldType.clone(); } @@ -375,6 +483,7 @@ public boolean equals(Object o) { } TextFieldType that = (TextFieldType) o; return fielddata == that.fielddata + && indexPhrases == that.indexPhrases && Objects.equals(prefixFieldType, that.prefixFieldType) && fielddataMinFrequency == that.fielddataMinFrequency && fielddataMaxFrequency == that.fielddataMaxFrequency @@ -383,7 +492,7 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(super.hashCode(), fielddata, prefixFieldType, + return Objects.hash(super.hashCode(), fielddata, indexPhrases, prefixFieldType, fielddataMinFrequency, fielddataMaxFrequency, fielddataMinSegmentSize); } @@ -405,6 +514,9 @@ else if (otherType.prefixFieldType == null) { conflicts.add("mapper [" + name() + "] has different [index_prefixes] settings"); } } + if (this.indexPhrases != otherType.indexPhrases) { + conflicts.add("mapper [" + name() + "] has different [index_phrases] settings"); + } if (strict) { if (fielddata() != otherType.fielddata()) { conflicts.add("mapper [" + name() + "] is used by multiple types. Set update_all_types to true to update [fielddata] " @@ -466,6 +578,11 @@ void setPrefixFieldType(PrefixFieldType prefixFieldType) { this.prefixFieldType = prefixFieldType; } + void setIndexPhrases(boolean indexPhrases) { + checkIfFrozen(); + this.indexPhrases = indexPhrases; + } + public PrefixFieldType getPrefixFieldType() { return this.prefixFieldType; } @@ -505,6 +622,92 @@ public Query nullValueQuery() { return termQuery(nullValue(), null); } + public Query phraseQuery(String field, TokenStream stream, int slop, boolean enablePosIncrements) throws IOException { + + if (indexPhrases && slop == 0 && hasGaps(cache(stream)) == false) { + stream = new FixedShingleFilter(stream, 2); + field = field + FAST_PHRASE_SUFFIX; + } + PhraseQuery.Builder builder = new PhraseQuery.Builder(); + builder.setSlop(slop); + + TermToBytesRefAttribute termAtt = stream.getAttribute(TermToBytesRefAttribute.class); + PositionIncrementAttribute posIncrAtt = stream.getAttribute(PositionIncrementAttribute.class); + int position = -1; + + stream.reset(); + while (stream.incrementToken()) { + if (enablePosIncrements) { + position += posIncrAtt.getPositionIncrement(); + } + else { + position += 1; + } + builder.add(new Term(field, termAtt.getBytesRef()), position); + } + + return builder.build(); + } + + @Override + public Query multiPhraseQuery(String field, TokenStream stream, int slop, boolean enablePositionIncrements) throws IOException { + + if (indexPhrases && slop == 0 && hasGaps(cache(stream)) == false) { + stream = new FixedShingleFilter(stream, 2); + field = field + FAST_PHRASE_SUFFIX; + } + + MultiPhraseQuery.Builder mpqb = new MultiPhraseQuery.Builder(); + mpqb.setSlop(slop); + + TermToBytesRefAttribute termAtt = stream.getAttribute(TermToBytesRefAttribute.class); + + PositionIncrementAttribute posIncrAtt = stream.getAttribute(PositionIncrementAttribute.class); + int position = -1; + + List multiTerms = new ArrayList<>(); + stream.reset(); + while (stream.incrementToken()) { + int positionIncrement = posIncrAtt.getPositionIncrement(); + + if (positionIncrement > 0 && multiTerms.size() > 0) { + if (enablePositionIncrements) { + mpqb.add(multiTerms.toArray(new Term[0]), position); + } else { + mpqb.add(multiTerms.toArray(new Term[0])); + } + multiTerms.clear(); + } + position += positionIncrement; + multiTerms.add(new Term(field, termAtt.getBytesRef())); + } + + if (enablePositionIncrements) { + mpqb.add(multiTerms.toArray(new Term[0]), position); + } else { + mpqb.add(multiTerms.toArray(new Term[0])); + } + return mpqb.build(); + } + + private static CachingTokenFilter cache(TokenStream in) { + if (in instanceof CachingTokenFilter) { + return (CachingTokenFilter) in; + } + return new CachingTokenFilter(in); + } + + private static boolean hasGaps(CachingTokenFilter stream) throws IOException { + PositionIncrementAttribute posIncAtt = stream.getAttribute(PositionIncrementAttribute.class); + stream.reset(); + while (stream.incrementToken()) { + if (posIncAtt.getPositionIncrement() > 1) { + return true; + } + } + return false; + } + @Override public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName) { if (fielddata == false) { @@ -520,8 +723,9 @@ public IndexFieldData.Builder fielddataBuilder(String fullyQualifiedIndexName) { private Boolean includeInAll; private int positionIncrementGap; private PrefixFieldMapper prefixFieldMapper; + private PhraseFieldMapper phraseFieldMapper; - protected TextFieldMapper(String simpleName, MappedFieldType fieldType, MappedFieldType defaultFieldType, + protected TextFieldMapper(String simpleName, TextFieldType fieldType, MappedFieldType defaultFieldType, int positionIncrementGap, Boolean includeInAll, PrefixFieldMapper prefixFieldMapper, Settings indexSettings, MultiFields multiFields, CopyTo copyTo) { super(simpleName, fieldType, defaultFieldType, indexSettings, multiFields, copyTo); @@ -533,6 +737,7 @@ protected TextFieldMapper(String simpleName, MappedFieldType fieldType, MappedFi this.positionIncrementGap = positionIncrementGap; this.includeInAll = includeInAll; this.prefixFieldMapper = prefixFieldMapper; + this.phraseFieldMapper = fieldType.indexPhrases ? new PhraseFieldMapper(new PhraseFieldType(fieldType), indexSettings) : null; } @Override @@ -575,15 +780,25 @@ protected void parseCreateField(ParseContext context, List field if (prefixFieldMapper != null) { prefixFieldMapper.addField(value, fields); } + if (phraseFieldMapper != null) { + fields.add(new Field(phraseFieldMapper.fieldType.name(), value, phraseFieldMapper.fieldType)); + } } } @Override public Iterator iterator() { - if (prefixFieldMapper == null) { + List subIterators = new ArrayList<>(); + if (prefixFieldMapper != null) { + subIterators.add(prefixFieldMapper); + } + if (phraseFieldMapper != null) { + subIterators.add(phraseFieldMapper); + } + if (subIterators.size() == 0) { return super.iterator(); } - return Iterators.concat(super.iterator(), Collections.singleton(prefixFieldMapper).iterator()); + return Iterators.concat(super.iterator(), subIterators.iterator()); } @Override @@ -603,6 +818,10 @@ else if (this.prefixFieldMapper != null || mw.prefixFieldMapper != null) { throw new IllegalArgumentException("mapper [" + name() + "] has different index_prefix settings, current [" + this.prefixFieldMapper + "], merged [" + mw.prefixFieldMapper + "]"); } + else if (this.fieldType().indexPhrases != mw.fieldType().indexPhrases) { + throw new IllegalArgumentException("mapper [" + name() + "] has different index_phrases settings, current [" + + this.fieldType().indexPhrases + "], merged [" + mw.fieldType().indexPhrases + "]"); + } } @Override @@ -649,5 +868,8 @@ protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, if (fieldType().prefixFieldType != null) { fieldType().prefixFieldType.doXContent(builder); } + if (fieldType().indexPhrases) { + builder.field("index_phrases", fieldType().indexPhrases); + } } } diff --git a/server/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java b/server/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java index 445720cb934ca..1b7b6f92df80b 100644 --- a/server/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java +++ b/server/src/main/java/org/elasticsearch/index/query/MatchPhraseQueryBuilder.java @@ -28,6 +28,7 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.index.mapper.MappedFieldType; import org.elasticsearch.index.search.MatchQuery; import org.elasticsearch.index.search.MatchQuery.ZeroTermsQuery; diff --git a/server/src/main/java/org/elasticsearch/index/search/MatchQuery.java b/server/src/main/java/org/elasticsearch/index/search/MatchQuery.java index 052bc8d1b077f..f6449771c13ec 100644 --- a/server/src/main/java/org/elasticsearch/index/search/MatchQuery.java +++ b/server/src/main/java/org/elasticsearch/index/search/MatchQuery.java @@ -354,16 +354,14 @@ protected Query newSynonymQuery(Term[] terms) { @Override protected Query analyzePhrase(String field, TokenStream stream, int slop) throws IOException { - if (hasPositions(mapper) == false) { - IllegalStateException exc = - new IllegalStateException("field:[" + field + "] was indexed without position data; cannot run PhraseQuery"); + IllegalStateException e = checkForPositions(field); + if (e != null) { if (lenient) { - return newLenientFieldQuery(field, exc); - } else { - throw exc; + return newLenientFieldQuery(field, e); } + throw e; } - Query query = super.analyzePhrase(field, stream, slop); + Query query = mapper.phraseQuery(field, stream, slop, enablePositionIncrements); if (query instanceof PhraseQuery) { // synonyms that expand to multiple terms can return a phrase query. return blendPhraseQuery((PhraseQuery) query, mapper); @@ -371,6 +369,25 @@ protected Query analyzePhrase(String field, TokenStream stream, int slop) throws return query; } + @Override + protected Query analyzeMultiPhrase(String field, TokenStream stream, int slop) throws IOException { + IllegalStateException e = checkForPositions(field); + if (e != null) { + if (lenient) { + return newLenientFieldQuery(field, e); + } + throw e; + } + return mapper.multiPhraseQuery(field, stream, slop, enablePositionIncrements); + } + + private IllegalStateException checkForPositions(String field) { + if (hasPositions(mapper) == false) { + return new IllegalStateException("field:[" + field + "] was indexed without position data; cannot run PhraseQuery"); + } + return null; + } + /** * Checks if graph analysis should be enabled for the field depending * on the provided {@link Analyzer} diff --git a/server/src/test/java/org/elasticsearch/index/mapper/TextFieldMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/TextFieldMapperTests.java index a0e6d309c75bc..5a4c06626024c 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/TextFieldMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/TextFieldMapperTests.java @@ -19,6 +19,8 @@ package org.elasticsearch.index.mapper; +import org.apache.lucene.analysis.TokenStream; +import org.apache.lucene.analysis.tokenattributes.CharTermAttribute; import org.apache.lucene.document.FieldType; import org.apache.lucene.index.DocValuesType; import org.apache.lucene.index.IndexOptions; @@ -29,6 +31,8 @@ import org.apache.lucene.index.Term; import org.apache.lucene.index.TermsEnum; import org.apache.lucene.search.ConstantScoreQuery; +import org.apache.lucene.search.MultiPhraseQuery; +import org.apache.lucene.search.PhraseQuery; import org.apache.lucene.search.PrefixQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; @@ -38,6 +42,7 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.compress.CompressedXContent; import org.elasticsearch.common.lucene.uid.Versions; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; @@ -47,7 +52,9 @@ import org.elasticsearch.index.engine.Engine; import org.elasticsearch.index.mapper.MapperService.MergeReason; import org.elasticsearch.index.mapper.TextFieldMapper.TextFieldType; +import org.elasticsearch.index.query.MatchPhraseQueryBuilder; import org.elasticsearch.index.query.QueryShardContext; +import org.elasticsearch.index.search.MatchQuery; import org.elasticsearch.index.shard.IndexShard; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.ESSingleNodeTestCase; @@ -65,6 +72,7 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.core.Is.is; public class TextFieldMapperTests extends ESSingleNodeTestCase { @@ -73,7 +81,13 @@ public class TextFieldMapperTests extends ESSingleNodeTestCase { @Before public void setup() { - indexService = createIndex("test"); + Settings settings = Settings.builder() + .put("index.analysis.filter.mySynonyms.type", "synonym") + .putList("index.analysis.filter.mySynonyms.synonyms", Collections.singletonList("car, auto")) + .put("index.analysis.analyzer.synonym.tokenizer", "standard") + .put("index.analysis.analyzer.synonym.filter", "mySynonyms") + .build(); + indexService = createIndex("test", settings); parser = indexService.mapperService().documentMapperParser(); } @@ -670,6 +684,102 @@ public void testIndexPrefixIndexTypes() throws IOException { } } + public void testFastPhraseMapping() throws IOException { + + QueryShardContext queryShardContext = indexService.newQueryShardContext( + randomInt(20), null, () -> { + throw new UnsupportedOperationException(); + }, null); + + String mapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type") + .startObject("properties") + .startObject("field") + .field("type", "text") + .field("analyzer", "english") + .field("index_phrases", true) + .endObject() + .startObject("synfield") + .field("type", "text") + .field("analyzer", "synonym") + .field("index_phrases", true) + .endObject() + .endObject() + .endObject().endObject()); + + DocumentMapper mapper = parser.parse("type", new CompressedXContent(mapping)); + assertEquals(mapping, mapper.mappingSource().toString()); + + queryShardContext.getMapperService().merge("type", new CompressedXContent(mapping), MergeReason.MAPPING_UPDATE, true); + + Query q = new MatchPhraseQueryBuilder("field", "two words").toQuery(queryShardContext); + assertThat(q, is(new PhraseQuery("field._index_phrase", "two word"))); + + Query q2 = new MatchPhraseQueryBuilder("field", "three words here").toQuery(queryShardContext); + assertThat(q2, is(new PhraseQuery("field._index_phrase", "three word", "word here"))); + + Query q3 = new MatchPhraseQueryBuilder("field", "two words").slop(1).toQuery(queryShardContext); + assertThat(q3, is(new PhraseQuery(1, "field", "two", "word"))); + + Query q4 = new MatchPhraseQueryBuilder("field", "singleton").toQuery(queryShardContext); + assertThat(q4, is(new TermQuery(new Term("field", "singleton")))); + + Query q5 = new MatchPhraseQueryBuilder("field", "sparkle a stopword").toQuery(queryShardContext); + assertThat(q5, + is(new PhraseQuery.Builder().add(new Term("field", "sparkl")).add(new Term("field", "stopword"), 2).build())); + + Query q6 = new MatchPhraseQueryBuilder("synfield", "motor car").toQuery(queryShardContext); + assertThat(q6, is(new MultiPhraseQuery.Builder() + .add(new Term[]{ + new Term("synfield._index_phrase", "motor car"), + new Term("synfield._index_phrase", "motor auto")}) + .build())); + + ParsedDocument doc = mapper.parse(SourceToParse.source("test", "type", "1", BytesReference + .bytes(XContentFactory.jsonBuilder() + .startObject() + .field("field", "Some English text that is going to be very useful") + .endObject()), + XContentType.JSON)); + + IndexableField[] fields = doc.rootDoc().getFields("field._index_phrase"); + assertEquals(1, fields.length); + + try (TokenStream ts = fields[0].tokenStream(queryShardContext.getMapperService().indexAnalyzer(), null)) { + CharTermAttribute termAtt = ts.addAttribute(CharTermAttribute.class); + ts.reset(); + assertTrue(ts.incrementToken()); + assertEquals("some english", termAtt.toString()); + } + + { + String badConfigMapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type") + .startObject("properties").startObject("field") + .field("type", "text") + .field("index", "false") + .field("index_phrases", true) + .endObject().endObject() + .endObject().endObject()); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + () -> parser.parse("type", new CompressedXContent(badConfigMapping)) + ); + assertThat(e.getMessage(), containsString("Cannot set index_phrases on unindexed field [field]")); + } + + { + String badConfigMapping = Strings.toString(XContentFactory.jsonBuilder().startObject().startObject("type") + .startObject("properties").startObject("field") + .field("type", "text") + .field("index_options", "freqs") + .field("index_phrases", true) + .endObject().endObject() + .endObject().endObject()); + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + () -> parser.parse("type", new CompressedXContent(badConfigMapping)) + ); + assertThat(e.getMessage(), containsString("Cannot set index_phrases on field [field] if positions are not enabled")); + } + } + public void testIndexPrefixMapping() throws IOException { QueryShardContext queryShardContext = indexService.newQueryShardContext( diff --git a/server/src/test/java/org/elasticsearch/index/mapper/TextFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/TextFieldTypeTests.java index d0eacfad44056..877553bacf919 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/TextFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/TextFieldTypeTests.java @@ -68,6 +68,13 @@ public void modify(MappedFieldType ft) { tft.setFielddataMinSegmentSize(1000); } }); + addModifier(new Modifier("index_phrases", false) { + @Override + public void modify(MappedFieldType ft) { + TextFieldMapper.TextFieldType tft = (TextFieldMapper.TextFieldType) ft; + tft.setIndexPhrases(true); + } + }); addModifier(new Modifier("index_prefixes", false) { @Override public void modify(MappedFieldType ft) { From 5e38a350d05cadb4ca0f2bbf200cb5c4b9317772 Mon Sep 17 00:00:00 2001 From: Ioannis Kakavas Date: Mon, 4 Jun 2018 13:12:32 +0300 Subject: [PATCH 04/21] Reuse expiration date of trial licenses (#31033) Retain the expiryDate for trial licenses (#30950) While updating the license signature to the new license spec retain the trial license expiration date to that of the existing license. Resolves #30882 --- .../license/StartupSelfGeneratedLicenseTask.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/StartupSelfGeneratedLicenseTask.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/StartupSelfGeneratedLicenseTask.java index 823283ac5a852..13d6326f3ce1d 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/StartupSelfGeneratedLicenseTask.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/StartupSelfGeneratedLicenseTask.java @@ -61,10 +61,10 @@ public ClusterState execute(ClusterState currentState) throws Exception { "]. Must be trial or basic."); } return updateWithLicense(currentState, type); - } else if (LicenseUtils.licenseNeedsExtended(currentLicensesMetaData.getLicense())) { - return extendBasic(currentState, currentLicensesMetaData); } else if (LicenseUtils.signatureNeedsUpdate(currentLicensesMetaData.getLicense())) { return updateLicenseSignature(currentState, currentLicensesMetaData); + } else if (LicenseUtils.licenseNeedsExtended(currentLicensesMetaData.getLicense())) { + return extendBasic(currentState, currentLicensesMetaData); } else { return currentState; } @@ -75,11 +75,10 @@ private ClusterState updateLicenseSignature(ClusterState currentState, LicensesM MetaData.Builder mdBuilder = MetaData.builder(currentState.metaData()); String type = license.type(); long issueDate = license.issueDate(); - long expiryDate; - if ("basic".equals(type)) { + long expiryDate = license.expiryDate(); + // extend the basic license expiration date if needed since extendBasic will not be called now + if ("basic".equals(type) && expiryDate != LicenseService.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS) { expiryDate = LicenseService.BASIC_SELF_GENERATED_LICENSE_EXPIRATION_MILLIS; - } else { - expiryDate = issueDate + LicenseService.NON_BASIC_SELF_GENERATED_LICENSE_DURATION.getMillis(); } License.Builder specBuilder = License.builder() .uid(license.uid()) @@ -92,6 +91,8 @@ private ClusterState updateLicenseSignature(ClusterState currentState, LicensesM Version trialVersion = currentLicenseMetaData.getMostRecentTrialVersion(); LicensesMetaData newLicenseMetadata = new LicensesMetaData(selfGeneratedLicense, trialVersion); mdBuilder.putCustom(LicensesMetaData.TYPE, newLicenseMetadata); + logger.info("Updating existing license to the new version.\n\nOld license:\n {}\n\n New license:\n{}", + license, newLicenseMetadata.getLicense()); return ClusterState.builder(currentState).metaData(mdBuilder).build(); } From 6681dc035ecf5251faa810540f08372d786c9bcb Mon Sep 17 00:00:00 2001 From: Jim Ferenczi Date: Mon, 4 Jun 2018 12:13:55 +0200 Subject: [PATCH 05/21] Remove wrong link in index phrases doc Relates #30450 --- docs/reference/mapping/types/text.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/reference/mapping/types/text.asciidoc b/docs/reference/mapping/types/text.asciidoc index fd5bb312ef15c..e2336bd5cb066 100644 --- a/docs/reference/mapping/types/text.asciidoc +++ b/docs/reference/mapping/types/text.asciidoc @@ -96,7 +96,7 @@ The following parameters are accepted by `text` fields: the expense of a larger index. Accepts an <> -<>:: +`index_phrases`:: If enabled, two-term word combinations ('shingles') are indexed into a separate field. This allows exact phrase queries to run more efficiently, at the expense From 165d357af7d9b4590f40e6634cfa883a8d999616 Mon Sep 17 00:00:00 2001 From: Michael Russell Date: Mon, 4 Jun 2018 13:00:57 +0200 Subject: [PATCH 06/21] [Docs] Fix typo in watcher conditions documentation (#30989) --- x-pack/docs/en/watcher/condition.asciidoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/docs/en/watcher/condition.asciidoc b/x-pack/docs/en/watcher/condition.asciidoc index 50424dc132a43..01f55f9b6682a 100644 --- a/x-pack/docs/en/watcher/condition.asciidoc +++ b/x-pack/docs/en/watcher/condition.asciidoc @@ -13,7 +13,7 @@ in the watch payload to determine whether or not to execute the watch actions. * <>: compare an array of values in the watch payload to a given value to determine whether or not to execute the watch actions. -* <>: use a script to determine wehther or not to +* <>: use a script to determine whether or not to execute the watch actions. NOTE: If you omit the condition definition from a watch, the condition defaults From 78ba1c4d340cad8ac183435ca8eb6e6c9871380d Mon Sep 17 00:00:00 2001 From: Daniel Mitterdorfer Date: Mon, 4 Jun 2018 14:03:01 +0200 Subject: [PATCH 07/21] Mute MatchPhrase*QueryBuilderTests Relates #31061 --- .../index/query/MatchPhrasePrefixQueryBuilderTests.java | 9 +++++++++ .../index/query/MatchPhraseQueryBuilderTests.java | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/server/src/test/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilderTests.java index b4d5f98fe0b47..00701adc449c3 100644 --- a/server/src/test/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/MatchPhrasePrefixQueryBuilderTests.java @@ -99,6 +99,15 @@ protected void doAssertLuceneQuery(MatchPhrasePrefixQueryBuilder queryBuilder, Q .or(instanceOf(IndexOrDocValuesQuery.class)).or(instanceOf(MatchNoDocsQuery.class))); } + /** + * Overridden to allow for annotating with @AwaitsFix. Please remove this method after fixing. + */ + @Override + @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/31061") + public void testToQuery() throws IOException { + super.testToQuery(); + } + public void testIllegalValues() { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new MatchPhrasePrefixQueryBuilder(null, "value")); assertEquals("[match_phrase_prefix] requires fieldName", e.getMessage()); diff --git a/server/src/test/java/org/elasticsearch/index/query/MatchPhraseQueryBuilderTests.java b/server/src/test/java/org/elasticsearch/index/query/MatchPhraseQueryBuilderTests.java index 1ac53992ebe8c..91a775dbf0256 100644 --- a/server/src/test/java/org/elasticsearch/index/query/MatchPhraseQueryBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/index/query/MatchPhraseQueryBuilderTests.java @@ -107,6 +107,15 @@ protected void doAssertLuceneQuery(MatchPhraseQueryBuilder queryBuilder, Query q .or(instanceOf(IndexOrDocValuesQuery.class)).or(instanceOf(MatchNoDocsQuery.class))); } + /** + * Overridden to allow for annotating with @AwaitsFix. Please remove this method after fixing. + */ + @Override + @AwaitsFix(bugUrl = "https://github.com/elastic/elasticsearch/issues/31061") + public void testToQuery() throws IOException { + super.testToQuery(); + } + public void testIllegalValues() { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> new MatchPhraseQueryBuilder(null, "value")); assertEquals("[match_phrase] requires fieldName", e.getMessage()); From d773b4cdd4956392dc17317fa72acc4e46c164fc Mon Sep 17 00:00:00 2001 From: Boaz Leskes Date: Sun, 3 Jun 2018 21:51:08 +0200 Subject: [PATCH 08/21] Make Persistent Tasks implementations version and feature aware (#31045) With #31020 we introduced the ability for transport clients to indicate what features they support in order to make sure we don't serialize object to them they don't support. This PR adapts the serialization logic of persistent tasks to be aware of those features and not serialize tasks that aren't supported. Also, a version check is added for the future where we may add new tasks implementations and need to be able to indicate they shouldn't be serialized both to nodes and clients. As the implementation relies on the interface of `PersistentTaskParams`, these are no longer optional. That's acceptable as all current implementation have them and we plan to make `PersistentTaskParams` more central in the future. Relates to #30731 --- .../tribe/TribeServiceTests.java | 11 +++ .../elasticsearch/cluster/ClusterState.java | 8 +- .../elasticsearch/cluster/NamedDiffable.java | 13 +--- .../cluster/RestoreInProgress.java | 8 +- .../cluster/SnapshotsInProgress.java | 5 ++ .../cluster/metadata/IndexGraveyard.java | 9 ++- .../cluster/metadata/MetaData.java | 4 +- .../metadata/RepositoriesMetaData.java | 6 ++ .../io/stream/VersionedNamedWriteable.java | 38 ++++++++++ .../elasticsearch/ingest/IngestMetadata.java | 6 ++ .../NodePersistentTasksExecutor.java | 2 +- .../persistent/PersistentTaskParams.java | 5 +- .../PersistentTasksClusterService.java | 5 +- .../PersistentTasksCustomMetaData.java | 20 +++-- .../persistent/PersistentTasksExecutor.java | 6 +- .../persistent/PersistentTasksService.java | 2 +- .../persistent/StartPersistentTaskAction.java | 16 +++- .../elasticsearch/script/ScriptMetaData.java | 5 ++ .../cluster/ClusterChangedEventTests.java | 10 +++ .../elasticsearch/cluster/ClusterStateIT.java | 14 +++- .../cluster/FeatureAwareTests.java | 12 +-- .../cluster/SimpleClusterStateIT.java | 7 +- .../ClusterSerializationTests.java | 28 +------ .../cluster/service/ClusterSerivceTests.java | 6 ++ .../discovery/zen/ZenDiscoveryIT.java | 5 ++ .../gateway/GatewayMetaStateTests.java | 10 +++ .../PersistentTasksCustomMetaDataTests.java | 74 +++++++++++++++++++ .../PersistentTasksExecutorFullRestartIT.java | 10 +-- .../StartPersistentActionRequestTests.java | 17 ++--- .../persistent/TestPersistentTasksPlugin.java | 31 +++++++- .../decider/EnableAssignmentDeciderIT.java | 9 +-- .../DedicatedClusterSnapshotRestoreIT.java | 27 ++++++- .../org/elasticsearch/test/VersionUtils.java | 18 +++-- .../license/LicensesMetaData.java | 5 ++ .../elasticsearch/xpack/core/XPackPlugin.java | 9 +++ .../xpack/core/ml/action/OpenJobAction.java | 9 ++- .../core/ml/action/StartDatafeedAction.java | 10 ++- .../xpack/core/rollup/job/RollupJob.java | 10 ++- .../xpack/core/watcher/WatcherMetaData.java | 6 ++ 39 files changed, 382 insertions(+), 114 deletions(-) create mode 100644 server/src/main/java/org/elasticsearch/common/io/stream/VersionedNamedWriteable.java diff --git a/modules/tribe/src/test/java/org/elasticsearch/tribe/TribeServiceTests.java b/modules/tribe/src/test/java/org/elasticsearch/tribe/TribeServiceTests.java index c0f6deff787ac..6f4c8412c8f6a 100644 --- a/modules/tribe/src/test/java/org/elasticsearch/tribe/TribeServiceTests.java +++ b/modules/tribe/src/test/java/org/elasticsearch/tribe/TribeServiceTests.java @@ -19,6 +19,7 @@ package org.elasticsearch.tribe; +import org.elasticsearch.Version; import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.MergableCustomMetaData; import org.elasticsearch.cluster.NamedDiff; @@ -238,6 +239,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } + public static MergableCustomMetaData1 readFrom(StreamInput in) throws IOException { return readFrom(MergableCustomMetaData1::new, in); } @@ -270,6 +276,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } + public static MergableCustomMetaData2 readFrom(StreamInput in) throws IOException { return readFrom(MergableCustomMetaData2::new, in); } diff --git a/server/src/main/java/org/elasticsearch/cluster/ClusterState.java b/server/src/main/java/org/elasticsearch/cluster/ClusterState.java index 6bc555eae0bd9..276e00a2ba3db 100644 --- a/server/src/main/java/org/elasticsearch/cluster/ClusterState.java +++ b/server/src/main/java/org/elasticsearch/cluster/ClusterState.java @@ -22,7 +22,6 @@ import com.carrotsearch.hppc.cursors.IntObjectCursor; import com.carrotsearch.hppc.cursors.ObjectCursor; import com.carrotsearch.hppc.cursors.ObjectObjectCursor; - import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.cluster.block.ClusterBlock; import org.elasticsearch.cluster.block.ClusterBlocks; @@ -50,6 +49,7 @@ import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; +import org.elasticsearch.common.io.stream.VersionedNamedWriteable; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.ToXContentFragment; import org.elasticsearch.common.xcontent.XContentBuilder; @@ -122,7 +122,7 @@ default Optional getRequiredFeature() { * @param the type of the custom * @return true if the custom should be serialized and false otherwise */ - static boolean shouldSerializeCustom(final StreamOutput out, final T custom) { + static boolean shouldSerialize(final StreamOutput out, final T custom) { if (out.getVersion().before(custom.getMinimalSupportedVersion())) { return false; } @@ -748,13 +748,13 @@ public void writeTo(StreamOutput out) throws IOException { // filter out custom states not supported by the other node int numberOfCustoms = 0; for (final ObjectCursor cursor : customs.values()) { - if (FeatureAware.shouldSerializeCustom(out, cursor.value)) { + if (FeatureAware.shouldSerialize(out, cursor.value)) { numberOfCustoms++; } } out.writeVInt(numberOfCustoms); for (final ObjectCursor cursor : customs.values()) { - if (FeatureAware.shouldSerializeCustom(out, cursor.value)) { + if (FeatureAware.shouldSerialize(out, cursor.value)) { out.writeNamedWriteable(cursor.value); } } diff --git a/server/src/main/java/org/elasticsearch/cluster/NamedDiffable.java b/server/src/main/java/org/elasticsearch/cluster/NamedDiffable.java index b548b49fe1910..729523233d73d 100644 --- a/server/src/main/java/org/elasticsearch/cluster/NamedDiffable.java +++ b/server/src/main/java/org/elasticsearch/cluster/NamedDiffable.java @@ -19,17 +19,10 @@ package org.elasticsearch.cluster; -import org.elasticsearch.Version; -import org.elasticsearch.common.io.stream.NamedWriteable; +import org.elasticsearch.common.io.stream.VersionedNamedWriteable; /** - * Diff that also support NamedWriteable interface + * Diff that also support {@link VersionedNamedWriteable} interface */ -public interface NamedDiffable extends Diffable, NamedWriteable { - /** - * The minimal version of the recipient this custom object can be sent to - */ - default Version getMinimalSupportedVersion() { - return Version.CURRENT.minimumIndexCompatibilityVersion(); - } +public interface NamedDiffable extends Diffable, VersionedNamedWriteable { } diff --git a/server/src/main/java/org/elasticsearch/cluster/RestoreInProgress.java b/server/src/main/java/org/elasticsearch/cluster/RestoreInProgress.java index 5c036f94285e0..138788251c90a 100644 --- a/server/src/main/java/org/elasticsearch/cluster/RestoreInProgress.java +++ b/server/src/main/java/org/elasticsearch/cluster/RestoreInProgress.java @@ -20,14 +20,15 @@ package org.elasticsearch.cluster; import com.carrotsearch.hppc.cursors.ObjectObjectCursor; +import org.elasticsearch.Version; import org.elasticsearch.cluster.ClusterState.Custom; -import org.elasticsearch.snapshots.Snapshot; import org.elasticsearch.common.collect.ImmutableOpenMap; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.index.shard.ShardId; +import org.elasticsearch.snapshots.Snapshot; import java.io.IOException; import java.util.ArrayList; @@ -382,6 +383,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } + public static NamedDiff readDiffFrom(StreamInput in) throws IOException { return readDiffFrom(Custom.class, TYPE, in); } diff --git a/server/src/main/java/org/elasticsearch/cluster/SnapshotsInProgress.java b/server/src/main/java/org/elasticsearch/cluster/SnapshotsInProgress.java index 4325a3c456b54..7308d471afb9d 100644 --- a/server/src/main/java/org/elasticsearch/cluster/SnapshotsInProgress.java +++ b/server/src/main/java/org/elasticsearch/cluster/SnapshotsInProgress.java @@ -395,6 +395,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } + public static NamedDiff readDiffFrom(StreamInput in) throws IOException { return readDiffFrom(Custom.class, TYPE, in); } diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexGraveyard.java b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexGraveyard.java index 9167b28a67b86..74789aada3a46 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexGraveyard.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexGraveyard.java @@ -19,6 +19,7 @@ package org.elasticsearch.cluster.metadata; +import org.elasticsearch.Version; import org.elasticsearch.cluster.Diff; import org.elasticsearch.cluster.NamedDiff; import org.elasticsearch.common.ParseField; @@ -34,8 +35,6 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.Index; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; import java.io.IOException; import java.util.ArrayList; @@ -44,7 +43,6 @@ import java.util.EnumSet; import java.util.List; import java.util.Objects; -import java.util.concurrent.TimeUnit; /** * A collection of tombstones for explicitly marking indices as deleted in the cluster state. @@ -97,6 +95,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } + @Override public EnumSet context() { return MetaData.API_AND_GATEWAY; diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java b/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java index bb5e8e6fa48b2..9afbbf95ae14d 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/MetaData.java @@ -793,13 +793,13 @@ public void writeTo(StreamOutput out) throws IOException { // filter out custom states not supported by the other node int numberOfCustoms = 0; for (final ObjectCursor cursor : customs.values()) { - if (FeatureAware.shouldSerializeCustom(out, cursor.value)) { + if (FeatureAware.shouldSerialize(out, cursor.value)) { numberOfCustoms++; } } out.writeVInt(numberOfCustoms); for (final ObjectCursor cursor : customs.values()) { - if (FeatureAware.shouldSerializeCustom(out, cursor.value)) { + if (FeatureAware.shouldSerialize(out, cursor.value)) { out.writeNamedWriteable(cursor.value); } } diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/RepositoriesMetaData.java b/server/src/main/java/org/elasticsearch/cluster/metadata/RepositoriesMetaData.java index c813ba76e82dd..7bb72be0e1e18 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/RepositoriesMetaData.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/RepositoriesMetaData.java @@ -20,6 +20,7 @@ package org.elasticsearch.cluster.metadata; import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.Version; import org.elasticsearch.cluster.AbstractNamedDiffable; import org.elasticsearch.cluster.NamedDiff; import org.elasticsearch.cluster.metadata.MetaData.Custom; @@ -103,6 +104,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } + public RepositoriesMetaData(StreamInput in) throws IOException { RepositoryMetaData[] repository = new RepositoryMetaData[in.readVInt()]; for (int i = 0; i < repository.length; i++) { diff --git a/server/src/main/java/org/elasticsearch/common/io/stream/VersionedNamedWriteable.java b/server/src/main/java/org/elasticsearch/common/io/stream/VersionedNamedWriteable.java new file mode 100644 index 0000000000000..9eea2c00d56a6 --- /dev/null +++ b/server/src/main/java/org/elasticsearch/common/io/stream/VersionedNamedWriteable.java @@ -0,0 +1,38 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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 org.elasticsearch.common.io.stream; + +import org.elasticsearch.Version; + +/** + * A {@link NamedWriteable} that has a minimum version associated with it. + */ +public interface VersionedNamedWriteable extends NamedWriteable { + + /** + * Returns the name of the writeable object + */ + String getWriteableName(); + + /** + * The minimal version of the recipient this object can be sent to + */ + Version getMinimalSupportedVersion(); +} diff --git a/server/src/main/java/org/elasticsearch/ingest/IngestMetadata.java b/server/src/main/java/org/elasticsearch/ingest/IngestMetadata.java index ca8a5df845014..1e262adf8cf8d 100644 --- a/server/src/main/java/org/elasticsearch/ingest/IngestMetadata.java +++ b/server/src/main/java/org/elasticsearch/ingest/IngestMetadata.java @@ -19,6 +19,7 @@ package org.elasticsearch.ingest; +import org.elasticsearch.Version; import org.elasticsearch.cluster.Diff; import org.elasticsearch.cluster.DiffableUtils; import org.elasticsearch.cluster.NamedDiff; @@ -69,6 +70,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } + public Map getPipelines() { return pipelines; } diff --git a/server/src/main/java/org/elasticsearch/persistent/NodePersistentTasksExecutor.java b/server/src/main/java/org/elasticsearch/persistent/NodePersistentTasksExecutor.java index efed0aef9b807..bf42733ff54ac 100644 --- a/server/src/main/java/org/elasticsearch/persistent/NodePersistentTasksExecutor.java +++ b/server/src/main/java/org/elasticsearch/persistent/NodePersistentTasksExecutor.java @@ -35,7 +35,7 @@ public NodePersistentTasksExecutor(ThreadPool threadPool) { this.threadPool = threadPool; } - public void executeTask(@Nullable Params params, + public void executeTask(Params params, @Nullable Task.Status status, AllocatedPersistentTask task, PersistentTasksExecutor executor) { diff --git a/server/src/main/java/org/elasticsearch/persistent/PersistentTaskParams.java b/server/src/main/java/org/elasticsearch/persistent/PersistentTaskParams.java index a475a7cde174a..c91727a913f3a 100644 --- a/server/src/main/java/org/elasticsearch/persistent/PersistentTaskParams.java +++ b/server/src/main/java/org/elasticsearch/persistent/PersistentTaskParams.java @@ -19,12 +19,13 @@ package org.elasticsearch.persistent; -import org.elasticsearch.common.io.stream.NamedWriteable; +import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.common.io.stream.VersionedNamedWriteable; import org.elasticsearch.common.xcontent.ToXContentObject; /** * Parameters used to start persistent task */ -public interface PersistentTaskParams extends NamedWriteable, ToXContentObject { +public interface PersistentTaskParams extends VersionedNamedWriteable, ToXContentObject, ClusterState.FeatureAware { } diff --git a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksClusterService.java b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksClusterService.java index cf44556ee5ddc..1464279a814d5 100644 --- a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksClusterService.java +++ b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksClusterService.java @@ -29,7 +29,6 @@ import org.elasticsearch.cluster.metadata.MetaData; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.service.ClusterService; -import org.elasticsearch.common.Nullable; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.persistent.PersistentTasksCustomMetaData.Assignment; @@ -65,7 +64,7 @@ public PersistentTasksClusterService(Settings settings, PersistentTasksExecutorR * @param taskParams the task's parameters * @param listener the listener that will be called when task is started */ - public void createPersistentTask(String taskId, String taskName, @Nullable Params taskParams, + public void createPersistentTask(String taskId, String taskName, Params taskParams, ActionListener> listener) { clusterService.submitStateUpdateTask("create persistent task", new ClusterStateUpdateTask() { @Override @@ -225,7 +224,7 @@ public void clusterStateProcessed(String source, ClusterState oldState, ClusterS * @return a new {@link Assignment} */ private Assignment createAssignment(final String taskName, - final @Nullable Params taskParams, + final Params taskParams, final ClusterState currentState) { PersistentTasksExecutor persistentTasksExecutor = registry.getPersistentTaskExecutorSafe(taskName); diff --git a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java index bdee87cc77c51..4b1ba3e11e372 100644 --- a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java +++ b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java @@ -49,8 +49,8 @@ import java.util.List; import java.util.Map; import java.util.Objects; -import java.util.Optional; import java.util.Set; +import java.util.function.Function; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -264,7 +264,6 @@ public static class PersistentTask

implements Wr private final String id; private final long allocationId; private final String taskName; - @Nullable private final P params; @Nullable private final Status status; @@ -314,7 +313,11 @@ public PersistentTask(StreamInput in) throws IOException { id = in.readString(); allocationId = in.readLong(); taskName = in.readString(); - params = (P) in.readOptionalNamedWriteable(PersistentTaskParams.class); + if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + params = (P) in.readNamedWriteable(PersistentTaskParams.class); + } else { + params = (P) in.readOptionalNamedWriteable(PersistentTaskParams.class); + } status = in.readOptionalNamedWriteable(Task.Status.class); assignment = new Assignment(in.readOptionalString(), in.readString()); allocationIdOnLastStatusUpdate = in.readOptionalLong(); @@ -325,7 +328,11 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(id); out.writeLong(allocationId); out.writeString(taskName); - out.writeOptionalNamedWriteable(params); + if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + out.writeNamedWriteable(params); + } else { + out.writeOptionalNamedWriteable(params); + } out.writeOptionalNamedWriteable(status); out.writeOptionalString(assignment.executorNode); out.writeString(assignment.explanation); @@ -500,7 +507,10 @@ public PersistentTasksCustomMetaData(StreamInput in) throws IOException { @Override public void writeTo(StreamOutput out) throws IOException { out.writeLong(lastAllocationId); - out.writeMap(tasks, StreamOutput::writeString, (stream, value) -> value.writeTo(stream)); + Map> filteredTasks = tasks.values().stream() + .filter(t -> ClusterState.FeatureAware.shouldSerialize(out, t.getParams())) + .collect(Collectors.toMap(PersistentTask::getId, Function.identity())); + out.writeMap(filteredTasks, StreamOutput::writeString, (stream, value) -> value.writeTo(stream)); } public static NamedDiff readDiffFrom(StreamInput in) throws IOException { diff --git a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksExecutor.java b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksExecutor.java index 0a1e2095934ef..de75b1ff54085 100644 --- a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksExecutor.java +++ b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksExecutor.java @@ -24,10 +24,10 @@ import org.elasticsearch.common.Nullable; import org.elasticsearch.common.component.AbstractComponent; import org.elasticsearch.common.settings.Settings; -import org.elasticsearch.tasks.Task; -import org.elasticsearch.tasks.TaskId; import org.elasticsearch.persistent.PersistentTasksCustomMetaData.Assignment; import org.elasticsearch.persistent.PersistentTasksCustomMetaData.PersistentTask; +import org.elasticsearch.tasks.Task; +import org.elasticsearch.tasks.TaskId; import java.util.Map; import java.util.function.Predicate; @@ -118,7 +118,7 @@ protected String getDescription(PersistentTask taskInProgress) { * NOTE: The nodeOperation has to throw an exception, trigger task.markAsCompleted() or task.completeAndNotifyIfNeeded() methods to * indicate that the persistent task has finished. */ - protected abstract void nodeOperation(AllocatedPersistentTask task, @Nullable Params params, @Nullable Task.Status status); + protected abstract void nodeOperation(AllocatedPersistentTask task, Params params, @Nullable Task.Status status); public String getExecutor() { return executor; diff --git a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksService.java b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksService.java index 482491fc3f7e9..e3d7020f4e037 100644 --- a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksService.java +++ b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksService.java @@ -69,7 +69,7 @@ public PersistentTasksService(Settings settings, ClusterService clusterService, */ public void sendStartRequest(final String taskId, final String taskName, - final @Nullable Params taskParams, + final Params taskParams, final ActionListener> listener) { @SuppressWarnings("unchecked") final ActionListener> wrappedListener = diff --git a/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java b/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java index 3b988939879c5..d2ebf7abbe737 100644 --- a/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java +++ b/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java @@ -18,6 +18,7 @@ */ package org.elasticsearch.persistent; +import org.elasticsearch.Version; import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRequestValidationException; @@ -36,9 +37,9 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.persistent.PersistentTasksCustomMetaData.PersistentTask; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; -import org.elasticsearch.persistent.PersistentTasksCustomMetaData.PersistentTask; import java.io.IOException; import java.util.Objects; @@ -73,7 +74,6 @@ public static class Request extends MasterNodeRequest { private String taskId; - @Nullable private String taskName; private PersistentTaskParams params; @@ -93,7 +93,11 @@ public void readFrom(StreamInput in) throws IOException { super.readFrom(in); taskId = in.readString(); taskName = in.readString(); - params = in.readOptionalNamedWriteable(PersistentTaskParams.class); + if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + params = in.readNamedWriteable(PersistentTaskParams.class); + } else { + params = in.readOptionalNamedWriteable(PersistentTaskParams.class); + } } @Override @@ -101,7 +105,11 @@ public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); out.writeString(taskId); out.writeString(taskName); - out.writeOptionalNamedWriteable(params); + if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + out.writeNamedWriteable(params); + } else { + out.writeOptionalNamedWriteable(params); + } } @Override diff --git a/server/src/main/java/org/elasticsearch/script/ScriptMetaData.java b/server/src/main/java/org/elasticsearch/script/ScriptMetaData.java index 9505875ae1ebc..59d824eb313e0 100644 --- a/server/src/main/java/org/elasticsearch/script/ScriptMetaData.java +++ b/server/src/main/java/org/elasticsearch/script/ScriptMetaData.java @@ -383,6 +383,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } + @Override public EnumSet context() { return MetaData.ALL_CONTEXTS; diff --git a/server/src/test/java/org/elasticsearch/cluster/ClusterChangedEventTests.java b/server/src/test/java/org/elasticsearch/cluster/ClusterChangedEventTests.java index b7ea45dd13a3d..f79fef74e917f 100644 --- a/server/src/test/java/org/elasticsearch/cluster/ClusterChangedEventTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/ClusterChangedEventTests.java @@ -308,6 +308,11 @@ public String getWriteableName() { return "2"; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + @Override public EnumSet context() { return EnumSet.of(MetaData.XContentContext.GATEWAY); @@ -324,6 +329,11 @@ public String getWriteableName() { return "1"; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + @Override public EnumSet context() { return EnumSet.of(MetaData.XContentContext.GATEWAY); diff --git a/server/src/test/java/org/elasticsearch/cluster/ClusterStateIT.java b/server/src/test/java/org/elasticsearch/cluster/ClusterStateIT.java index 07a974a2ca771..2bf56e888148d 100644 --- a/server/src/test/java/org/elasticsearch/cluster/ClusterStateIT.java +++ b/server/src/test/java/org/elasticsearch/cluster/ClusterStateIT.java @@ -19,6 +19,7 @@ package org.elasticsearch.cluster; +import org.elasticsearch.Version; import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; import org.elasticsearch.client.Client; import org.elasticsearch.cluster.metadata.IndexGraveyard; @@ -73,7 +74,8 @@ @ESIntegTestCase.ClusterScope(scope = TEST) public class ClusterStateIT extends ESIntegTestCase { - public abstract static class Custom implements MetaData.Custom { + public abstract static + class Custom implements MetaData.Custom { private static final ParseField VALUE = new ParseField("value"); @@ -131,6 +133,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + @Override public Optional getRequiredFeature() { return Optional.of("node"); @@ -155,6 +162,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + /* * This custom should always be returned yet we randomize whether it has a required feature that the client is expected to have * versus not requiring any feature. We use a field to make the random choice exactly once. diff --git a/server/src/test/java/org/elasticsearch/cluster/FeatureAwareTests.java b/server/src/test/java/org/elasticsearch/cluster/FeatureAwareTests.java index 0f826e65248fe..b25d8ced1806d 100644 --- a/server/src/test/java/org/elasticsearch/cluster/FeatureAwareTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/FeatureAwareTests.java @@ -116,7 +116,7 @@ public void testVersion() { if (custom.getRequiredFeature().isPresent()) { out.setFeatures(Collections.singleton(custom.getRequiredFeature().get())); } - assertTrue(FeatureAware.shouldSerializeCustom(out, custom)); + assertTrue(FeatureAware.shouldSerialize(out, custom)); } { final BytesStreamOutput out = new BytesStreamOutput(); @@ -126,7 +126,7 @@ public void testVersion() { if (custom.getRequiredFeature().isPresent() && randomBoolean()) { out.setFeatures(Collections.singleton(custom.getRequiredFeature().get())); } - assertFalse(FeatureAware.shouldSerializeCustom(out, custom)); + assertFalse(FeatureAware.shouldSerialize(out, custom)); } } } @@ -141,7 +141,7 @@ public void testFeature() { out.setVersion(afterVersion); assertTrue(custom.getRequiredFeature().isPresent()); out.setFeatures(Collections.singleton(custom.getRequiredFeature().get())); - assertTrue(FeatureAware.shouldSerializeCustom(out, custom)); + assertTrue(FeatureAware.shouldSerialize(out, custom)); } { // the feature is present and the client is a transport client @@ -149,7 +149,7 @@ public void testFeature() { out.setVersion(afterVersion); assertTrue(custom.getRequiredFeature().isPresent()); out.setFeatures(new HashSet<>(Arrays.asList(custom.getRequiredFeature().get(), TransportClient.TRANSPORT_CLIENT_FEATURE))); - assertTrue(FeatureAware.shouldSerializeCustom(out, custom)); + assertTrue(FeatureAware.shouldSerialize(out, custom)); } } @@ -161,14 +161,14 @@ public void testMissingFeature() { // the feature is missing but we should serialize it anyway because the client is not a transport client final BytesStreamOutput out = new BytesStreamOutput(); out.setVersion(afterVersion); - assertTrue(FeatureAware.shouldSerializeCustom(out, custom)); + assertTrue(FeatureAware.shouldSerialize(out, custom)); } { // the feature is missing and we should not serialize it because the client is a transport client final BytesStreamOutput out = new BytesStreamOutput(); out.setVersion(afterVersion); out.setFeatures(Collections.singleton(TransportClient.TRANSPORT_CLIENT_FEATURE)); - assertFalse(FeatureAware.shouldSerializeCustom(out, custom)); + assertFalse(FeatureAware.shouldSerialize(out, custom)); } } diff --git a/server/src/test/java/org/elasticsearch/cluster/SimpleClusterStateIT.java b/server/src/test/java/org/elasticsearch/cluster/SimpleClusterStateIT.java index 8b246ecc2d3de..0ba3de4381891 100644 --- a/server/src/test/java/org/elasticsearch/cluster/SimpleClusterStateIT.java +++ b/server/src/test/java/org/elasticsearch/cluster/SimpleClusterStateIT.java @@ -19,6 +19,7 @@ package org.elasticsearch.cluster; +import org.elasticsearch.Version; import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResponse; import org.elasticsearch.action.support.IndicesOptions; @@ -37,7 +38,6 @@ import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.ByteSizeValue; -import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.IndexNotFoundException; @@ -304,6 +304,11 @@ public String getWriteableName() { return "test"; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + @Override public void writeTo(StreamOutput out) throws IOException { out.writeInt(value); diff --git a/server/src/test/java/org/elasticsearch/cluster/serialization/ClusterSerializationTests.java b/server/src/test/java/org/elasticsearch/cluster/serialization/ClusterSerializationTests.java index 6a2754a0d846c..52c217332f76f 100644 --- a/server/src/test/java/org/elasticsearch/cluster/serialization/ClusterSerializationTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/serialization/ClusterSerializationTests.java @@ -42,13 +42,12 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.snapshots.Snapshot; import org.elasticsearch.snapshots.SnapshotId; +import org.elasticsearch.test.VersionUtils; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import static org.elasticsearch.test.VersionUtils.randomVersionBetween; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; @@ -131,8 +130,9 @@ public void testSnapshotDeletionsInProgressSerialization() throws Exception { Diff diffs = clusterState.diff(ClusterState.EMPTY_STATE); - // serialize with current version BytesStreamOutput outStream = new BytesStreamOutput(); + Version version = VersionUtils.randomVersionBetween(random(), Version.CURRENT.minimumCompatibilityVersion(), Version.CURRENT); + outStream.setVersion(version); diffs.writeTo(outStream); StreamInput inStream = outStream.bytes().streamInput(); inStream = new NamedWriteableAwareStreamInput(inStream, new NamedWriteableRegistry(ClusterModule.getNamedWriteables())); @@ -141,28 +141,6 @@ public void testSnapshotDeletionsInProgressSerialization() throws Exception { assertThat(stateAfterDiffs.custom(RestoreInProgress.TYPE), includeRestore ? notNullValue() : nullValue()); assertThat(stateAfterDiffs.custom(SnapshotDeletionsInProgress.TYPE), notNullValue()); - // serialize with old version - outStream = new BytesStreamOutput(); - outStream.setVersion(Version.CURRENT.minimumIndexCompatibilityVersion()); - diffs.writeTo(outStream); - inStream = outStream.bytes().streamInput(); - inStream.setVersion(outStream.getVersion()); - inStream = new NamedWriteableAwareStreamInput(inStream, new NamedWriteableRegistry(ClusterModule.getNamedWriteables())); - serializedDiffs = ClusterState.readDiffFrom(inStream, clusterState.nodes().getLocalNode()); - stateAfterDiffs = serializedDiffs.apply(ClusterState.EMPTY_STATE); - assertThat(stateAfterDiffs.custom(RestoreInProgress.TYPE), includeRestore ? notNullValue() : nullValue()); - assertThat(stateAfterDiffs.custom(SnapshotDeletionsInProgress.TYPE), nullValue()); - - // remove the custom and try serializing again with old version - clusterState = ClusterState.builder(clusterState).removeCustom(SnapshotDeletionsInProgress.TYPE).incrementVersion().build(); - outStream = new BytesStreamOutput(); - diffs.writeTo(outStream); - inStream = outStream.bytes().streamInput(); - inStream = new NamedWriteableAwareStreamInput(inStream, new NamedWriteableRegistry(ClusterModule.getNamedWriteables())); - serializedDiffs = ClusterState.readDiffFrom(inStream, clusterState.nodes().getLocalNode()); - stateAfterDiffs = serializedDiffs.apply(stateAfterDiffs); - assertThat(stateAfterDiffs.custom(RestoreInProgress.TYPE), includeRestore ? notNullValue() : nullValue()); - assertThat(stateAfterDiffs.custom(SnapshotDeletionsInProgress.TYPE), nullValue()); } private ClusterState updateUsingSerialisedDiff(ClusterState original, Diff diff) throws IOException { diff --git a/server/src/test/java/org/elasticsearch/cluster/service/ClusterSerivceTests.java b/server/src/test/java/org/elasticsearch/cluster/service/ClusterSerivceTests.java index e7cbd04ce4b50..2cebd41a52c43 100644 --- a/server/src/test/java/org/elasticsearch/cluster/service/ClusterSerivceTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/service/ClusterSerivceTests.java @@ -18,6 +18,7 @@ */ package org.elasticsearch.cluster.service; +import org.elasticsearch.Version; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.Diff; import org.elasticsearch.common.io.stream.StreamOutput; @@ -43,6 +44,11 @@ public String getWriteableName() { return null; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + @Override public void writeTo(StreamOutput out) throws IOException { diff --git a/server/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java b/server/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java index e51177c318ca8..b7177fdf867af 100644 --- a/server/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java +++ b/server/src/test/java/org/elasticsearch/discovery/zen/ZenDiscoveryIT.java @@ -239,6 +239,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + @Override public EnumSet context() { return EnumSet.of(MetaData.XContentContext.GATEWAY, MetaData.XContentContext.SNAPSHOT); diff --git a/server/src/test/java/org/elasticsearch/gateway/GatewayMetaStateTests.java b/server/src/test/java/org/elasticsearch/gateway/GatewayMetaStateTests.java index cef3502a077c5..14f3c212c464c 100644 --- a/server/src/test/java/org/elasticsearch/gateway/GatewayMetaStateTests.java +++ b/server/src/test/java/org/elasticsearch/gateway/GatewayMetaStateTests.java @@ -492,6 +492,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + @Override public EnumSet context() { return EnumSet.of(MetaData.XContentContext.GATEWAY); @@ -510,6 +515,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + @Override public EnumSet context() { return EnumSet.of(MetaData.XContentContext.GATEWAY); diff --git a/server/src/test/java/org/elasticsearch/persistent/PersistentTasksCustomMetaDataTests.java b/server/src/test/java/org/elasticsearch/persistent/PersistentTasksCustomMetaDataTests.java index 67962b800d2cf..72e74359d3016 100644 --- a/server/src/test/java/org/elasticsearch/persistent/PersistentTasksCustomMetaDataTests.java +++ b/server/src/test/java/org/elasticsearch/persistent/PersistentTasksCustomMetaDataTests.java @@ -19,6 +19,8 @@ package org.elasticsearch.persistent; import org.elasticsearch.ResourceNotFoundException; +import org.elasticsearch.Version; +import org.elasticsearch.client.transport.TransportClient; import org.elasticsearch.cluster.Diff; import org.elasticsearch.cluster.NamedDiff; import org.elasticsearch.cluster.metadata.MetaData; @@ -26,8 +28,11 @@ import org.elasticsearch.common.ParseField; import org.elasticsearch.common.UUIDs; import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.io.stream.BytesStreamOutput; +import org.elasticsearch.common.io.stream.NamedWriteableAwareStreamInput; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry; +import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.ToXContent; @@ -43,13 +48,24 @@ import org.elasticsearch.tasks.Task; import org.elasticsearch.test.AbstractDiffableSerializationTestCase; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashSet; +import java.util.NoSuchElementException; +import java.util.Optional; +import java.util.Set; import static org.elasticsearch.cluster.metadata.MetaData.CONTEXT_MODE_GATEWAY; import static org.elasticsearch.cluster.metadata.MetaData.CONTEXT_MODE_SNAPSHOT; import static org.elasticsearch.persistent.PersistentTasksExecutor.NO_NODE_FOUND; +import static org.elasticsearch.test.VersionUtils.allReleasedVersions; +import static org.elasticsearch.test.VersionUtils.compatibleFutureVersion; +import static org.elasticsearch.test.VersionUtils.getFirstVersion; +import static org.elasticsearch.test.VersionUtils.getPreviousVersion; +import static org.elasticsearch.test.VersionUtils.randomVersionBetween; +import static org.hamcrest.Matchers.equalTo; public class PersistentTasksCustomMetaDataTests extends AbstractDiffableSerializationTestCase { @@ -228,7 +244,65 @@ public void testBuilder() { assertEquals(changed, builder.isChanged()); persistentTasks = builder.build(); } + } + + public void testMinVersionSerialization() throws IOException { + PersistentTasksCustomMetaData.Builder tasks = PersistentTasksCustomMetaData.builder(); + + Version minVersion = allReleasedVersions().stream().filter(Version::isRelease).findFirst().orElseThrow(NoSuchElementException::new); + final Version streamVersion = randomVersionBetween(random(), minVersion, getPreviousVersion(Version.CURRENT)); + tasks.addTask("test_compatible_version", TestPersistentTasksExecutor.NAME, + new TestParams(null, randomVersionBetween(random(), minVersion, streamVersion), + randomBoolean() ? Optional.empty() : Optional.of("test")), + randomAssignment()); + tasks.addTask("test_incompatible_version", TestPersistentTasksExecutor.NAME, + new TestParams(null, randomVersionBetween(random(), compatibleFutureVersion(streamVersion), Version.CURRENT), + randomBoolean() ? Optional.empty() : Optional.of("test")), + randomAssignment()); + final BytesStreamOutput out = new BytesStreamOutput(); + out.setVersion(streamVersion); + Set features = new HashSet<>(); + final boolean transportClient = randomBoolean(); + if (transportClient) { + features.add(TransportClient.TRANSPORT_CLIENT_FEATURE); + } + // if a transport client, then it must have the feature otherwise we add the feature randomly + if (transportClient || randomBoolean()) { + features.add("test"); + } + out.setFeatures(features); + tasks.build().writeTo(out); + + final StreamInput input = out.bytes().streamInput(); + input.setVersion(streamVersion); + PersistentTasksCustomMetaData read = + new PersistentTasksCustomMetaData(new NamedWriteableAwareStreamInput(input, getNamedWriteableRegistry())); + + assertThat(read.taskMap().keySet(), equalTo(Collections.singleton("test_compatible_version"))); + } + + public void testFeatureSerialization() throws IOException { + PersistentTasksCustomMetaData.Builder tasks = PersistentTasksCustomMetaData.builder(); + + Version minVersion = getFirstVersion(); + tasks.addTask("test_compatible", TestPersistentTasksExecutor.NAME, + new TestParams(null, randomVersionBetween(random(), minVersion, Version.CURRENT), + randomBoolean() ? Optional.empty() : Optional.of("existing")), + randomAssignment()); + tasks.addTask("test_incompatible", TestPersistentTasksExecutor.NAME, + new TestParams(null, randomVersionBetween(random(), minVersion, Version.CURRENT), Optional.of("non_existing")), + randomAssignment()); + final BytesStreamOutput out = new BytesStreamOutput(); + out.setVersion(Version.CURRENT); + Set features = new HashSet<>(); + features.add("existing"); + features.add(TransportClient.TRANSPORT_CLIENT_FEATURE); + out.setFeatures(features); + tasks.build().writeTo(out); + PersistentTasksCustomMetaData read = new PersistentTasksCustomMetaData( + new NamedWriteableAwareStreamInput(out.bytes().streamInput(), getNamedWriteableRegistry())); + assertThat(read.taskMap().keySet(), equalTo(Collections.singleton("test_compatible"))); } private Assignment randomAssignment() { diff --git a/server/src/test/java/org/elasticsearch/persistent/PersistentTasksExecutorFullRestartIT.java b/server/src/test/java/org/elasticsearch/persistent/PersistentTasksExecutorFullRestartIT.java index b67b7678332b7..0a7168ad9b287 100644 --- a/server/src/test/java/org/elasticsearch/persistent/PersistentTasksExecutorFullRestartIT.java +++ b/server/src/test/java/org/elasticsearch/persistent/PersistentTasksExecutorFullRestartIT.java @@ -20,12 +20,12 @@ import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.common.UUIDs; +import org.elasticsearch.persistent.PersistentTasksCustomMetaData.PersistentTask; +import org.elasticsearch.persistent.TestPersistentTasksPlugin.TestParams; +import org.elasticsearch.persistent.TestPersistentTasksPlugin.TestPersistentTasksExecutor; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.junit.annotations.TestLogging; -import org.elasticsearch.persistent.PersistentTasksCustomMetaData.PersistentTask; -import org.elasticsearch.persistent.TestPersistentTasksPlugin.TestPersistentTasksExecutor; -import org.elasticsearch.persistent.TestPersistentTasksPlugin.TestParams; import java.util.ArrayList; import java.util.Collection; @@ -35,8 +35,6 @@ import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThan; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; @ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, minNumDataNodes = 1) public class PersistentTasksExecutorFullRestartIT extends ESIntegTestCase { @@ -65,7 +63,7 @@ public void testFullClusterRestart() throws Exception { PlainActionFuture> future = new PlainActionFuture<>(); futures.add(future); taskIds[i] = UUIDs.base64UUID(); - service.sendStartRequest(taskIds[i], TestPersistentTasksExecutor.NAME, randomBoolean() ? null : new TestParams("Blah"), future); + service.sendStartRequest(taskIds[i], TestPersistentTasksExecutor.NAME, new TestParams("Blah"), future); } for (int i = 0; i < numberOfTasks; i++) { diff --git a/server/src/test/java/org/elasticsearch/persistent/StartPersistentActionRequestTests.java b/server/src/test/java/org/elasticsearch/persistent/StartPersistentActionRequestTests.java index 3b0fc2a3d0495..e4c5a26de9c0c 100644 --- a/server/src/test/java/org/elasticsearch/persistent/StartPersistentActionRequestTests.java +++ b/server/src/test/java/org/elasticsearch/persistent/StartPersistentActionRequestTests.java @@ -22,8 +22,8 @@ import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.NamedWriteableRegistry.Entry; import org.elasticsearch.persistent.StartPersistentTaskAction.Request; -import org.elasticsearch.persistent.TestPersistentTasksPlugin.TestPersistentTasksExecutor; import org.elasticsearch.persistent.TestPersistentTasksPlugin.TestParams; +import org.elasticsearch.persistent.TestPersistentTasksPlugin.TestPersistentTasksExecutor; import org.elasticsearch.test.AbstractStreamableTestCase; import java.util.Collections; @@ -32,17 +32,12 @@ public class StartPersistentActionRequestTests extends AbstractStreamableTestCas @Override protected Request createTestInstance() { - TestParams testParams; + TestParams testParams = new TestParams(); + if (randomBoolean()) { + testParams.setTestParam(randomAlphaOfLengthBetween(1, 20)); + } if (randomBoolean()) { - testParams = new TestParams(); - if (randomBoolean()) { - testParams.setTestParam(randomAlphaOfLengthBetween(1, 20)); - } - if (randomBoolean()) { - testParams.setExecutorNodeAttr(randomAlphaOfLengthBetween(1, 20)); - } - } else { - testParams = null; + testParams.setExecutorNodeAttr(randomAlphaOfLengthBetween(1, 20)); } return new Request(UUIDs.base64UUID(), randomAlphaOfLengthBetween(1, 20), testParams); } diff --git a/server/src/test/java/org/elasticsearch/persistent/TestPersistentTasksPlugin.java b/server/src/test/java/org/elasticsearch/persistent/TestPersistentTasksPlugin.java index 556d6d1983e63..9799036e0ea91 100644 --- a/server/src/test/java/org/elasticsearch/persistent/TestPersistentTasksPlugin.java +++ b/server/src/test/java/org/elasticsearch/persistent/TestPersistentTasksPlugin.java @@ -19,6 +19,7 @@ package org.elasticsearch.persistent; +import org.elasticsearch.Version; import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRequest; @@ -49,6 +50,8 @@ import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.persistent.PersistentTasksCustomMetaData.Assignment; +import org.elasticsearch.persistent.PersistentTasksCustomMetaData.PersistentTask; import org.elasticsearch.plugins.ActionPlugin; import org.elasticsearch.plugins.PersistentTaskPlugin; import org.elasticsearch.plugins.Plugin; @@ -57,8 +60,6 @@ import org.elasticsearch.tasks.TaskId; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.transport.TransportService; -import org.elasticsearch.persistent.PersistentTasksCustomMetaData.Assignment; -import org.elasticsearch.persistent.PersistentTasksCustomMetaData.PersistentTask; import java.io.IOException; import java.util.ArrayList; @@ -67,6 +68,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; @@ -120,6 +122,9 @@ public static class TestParams implements PersistentTaskParams { REQUEST_PARSER.declareString(constructorArg(), new ParseField("param")); } + private final Version minVersion; + private final Optional feature; + private String executorNodeAttr = null; private String responseNode = null; @@ -127,17 +132,25 @@ public static class TestParams implements PersistentTaskParams { private String testParam = null; public TestParams() { - + this((String)null); } public TestParams(String testParam) { + this(testParam, Version.CURRENT, Optional.empty()); + } + + public TestParams(String testParam, Version minVersion, Optional feature) { this.testParam = testParam; + this.minVersion = minVersion; + this.feature = feature; } public TestParams(StreamInput in) throws IOException { executorNodeAttr = in.readOptionalString(); responseNode = in.readOptionalString(); testParam = in.readOptionalString(); + minVersion = Version.readVersion(in); + feature = Optional.ofNullable(in.readOptionalString()); } @Override @@ -166,6 +179,8 @@ public void writeTo(StreamOutput out) throws IOException { out.writeOptionalString(executorNodeAttr); out.writeOptionalString(responseNode); out.writeOptionalString(testParam); + Version.writeVersion(minVersion, out); + out.writeOptionalString(feature.orElse(null)); } @Override @@ -194,6 +209,16 @@ public boolean equals(Object o) { public int hashCode() { return Objects.hash(executorNodeAttr, responseNode, testParam); } + + @Override + public Version getMinimalSupportedVersion() { + return minVersion; + } + + @Override + public Optional getRequiredFeature() { + return feature; + } } public static class Status implements Task.Status { diff --git a/server/src/test/java/org/elasticsearch/persistent/decider/EnableAssignmentDeciderIT.java b/server/src/test/java/org/elasticsearch/persistent/decider/EnableAssignmentDeciderIT.java index cf1cc89b3a18a..aeb4d9b3a9bfb 100644 --- a/server/src/test/java/org/elasticsearch/persistent/decider/EnableAssignmentDeciderIT.java +++ b/server/src/test/java/org/elasticsearch/persistent/decider/EnableAssignmentDeciderIT.java @@ -71,7 +71,7 @@ public void testEnableAssignmentAfterRestart() throws Exception { final CountDownLatch latch = new CountDownLatch(numberOfTasks); for (int i = 0; i < numberOfTasks; i++) { PersistentTasksService service = internalCluster().getInstance(PersistentTasksService.class); - service.sendStartRequest("task_" + i, TestPersistentTasksExecutor.NAME, randomTaskParams(), + service.sendStartRequest("task_" + i, TestPersistentTasksExecutor.NAME, new TestParams(randomAlphaOfLength(10)), new ActionListener>() { @Override public void onResponse(PersistentTask task) { @@ -163,11 +163,4 @@ private void resetPersistentTasksAssignment() { assertAcked(client().admin().cluster().prepareUpdateSettings().setPersistentSettings(settings)); } - /** Returns a random task parameter **/ - private static PersistentTaskParams randomTaskParams() { - if (randomBoolean()) { - return null; - } - return new TestParams(randomAlphaOfLength(10)); - } } diff --git a/server/src/test/java/org/elasticsearch/snapshots/DedicatedClusterSnapshotRestoreIT.java b/server/src/test/java/org/elasticsearch/snapshots/DedicatedClusterSnapshotRestoreIT.java index 1dc853db59467..5d2abdd149223 100644 --- a/server/src/test/java/org/elasticsearch/snapshots/DedicatedClusterSnapshotRestoreIT.java +++ b/server/src/test/java/org/elasticsearch/snapshots/DedicatedClusterSnapshotRestoreIT.java @@ -21,9 +21,9 @@ import com.carrotsearch.hppc.IntHashSet; import com.carrotsearch.hppc.IntSet; +import org.elasticsearch.Version; import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.admin.cluster.repositories.put.PutRepositoryResponse; -import org.elasticsearch.action.admin.cluster.repositories.verify.VerifyRepositoryResponse; import org.elasticsearch.action.admin.cluster.snapshots.create.CreateSnapshotResponse; import org.elasticsearch.action.admin.cluster.snapshots.delete.DeleteSnapshotResponse; import org.elasticsearch.action.admin.cluster.snapshots.get.GetSnapshotsResponse; @@ -1162,6 +1162,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + public static SnapshottableMetadata readFrom(StreamInput in) throws IOException { return readFrom(SnapshottableMetadata::new, in); } @@ -1193,6 +1198,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + public static NonSnapshottableMetadata readFrom(StreamInput in) throws IOException { return readFrom(NonSnapshottableMetadata::new, in); } @@ -1223,6 +1233,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + public static SnapshottableGatewayMetadata readFrom(StreamInput in) throws IOException { return readFrom(SnapshottableGatewayMetadata::new, in); } @@ -1253,6 +1268,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + public static NonSnapshottableGatewayMetadata readFrom(StreamInput in) throws IOException { return readFrom(NonSnapshottableGatewayMetadata::new, in); } @@ -1284,6 +1304,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT; + } + public static SnapshotableGatewayNoApiMetadata readFrom(StreamInput in) throws IOException { return readFrom(SnapshotableGatewayNoApiMetadata::new, in); } diff --git a/test/framework/src/main/java/org/elasticsearch/test/VersionUtils.java b/test/framework/src/main/java/org/elasticsearch/test/VersionUtils.java index 792f3fba123da..84c480b8d510b 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/VersionUtils.java +++ b/test/framework/src/main/java/org/elasticsearch/test/VersionUtils.java @@ -19,22 +19,19 @@ package org.elasticsearch.test; +import org.elasticsearch.Version; +import org.elasticsearch.common.Nullable; +import org.elasticsearch.common.collect.Tuple; + import java.util.ArrayList; import java.util.Collections; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Random; -import java.util.SortedSet; -import java.util.TreeSet; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.elasticsearch.Version; -import org.elasticsearch.common.Nullable; -import org.elasticsearch.common.collect.Tuple; - /** Utilities for selecting versions in tests */ public class VersionUtils { @@ -228,6 +225,13 @@ public static Version incompatibleFutureVersion(Version version) { return opt.get(); } + /** returns the first future compatible version */ + public static Version compatibleFutureVersion(Version version) { + final Optional opt = ALL_VERSIONS.stream().filter(version::before).filter(v -> v.isCompatible(version)).findAny(); + assert opt.isPresent() : "no future compatible version for " + version; + return opt.get(); + } + /** Returns the maximum {@link Version} that is compatible with the given version. */ public static Version maxCompatibleVersion(Version version) { final List compatible = ALL_VERSIONS.stream().filter(version::isCompatible).filter(version::onOrBefore) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensesMetaData.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensesMetaData.java index d9f7068b2181e..6d001dea516ac 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensesMetaData.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/license/LicensesMetaData.java @@ -108,6 +108,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } + @Override public EnumSet context() { return EnumSet.of(MetaData.XContentContext.GATEWAY); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java index 602f4bdbc079b..db36aabf7ac6a 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/XPackPlugin.java @@ -40,6 +40,7 @@ import org.elasticsearch.license.LicensesMetaData; import org.elasticsearch.license.Licensing; import org.elasticsearch.license.XPackLicenseState; +import org.elasticsearch.persistent.PersistentTaskParams; import org.elasticsearch.plugins.ExtensiblePlugin; import org.elasticsearch.plugins.ScriptPlugin; import org.elasticsearch.rest.RestController; @@ -331,4 +332,12 @@ default Optional getRequiredFeature() { } + public interface XPackPersistentTaskParams extends PersistentTaskParams { + + @Override + default Optional getRequiredFeature() { + return XPackClientPlugin.X_PACK_FEATURE; + } + } + } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/action/OpenJobAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/action/OpenJobAction.java index 9527c39a607c2..eb102cdc3a68a 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/action/OpenJobAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/action/OpenJobAction.java @@ -22,10 +22,10 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.tasks.Task; +import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.ml.MachineLearningField; import org.elasticsearch.xpack.core.ml.job.config.Job; import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper; -import org.elasticsearch.persistent.PersistentTaskParams; import java.io.IOException; import java.util.Objects; @@ -131,7 +131,7 @@ public String toString() { } } - public static class JobParams implements PersistentTaskParams { + public static class JobParams implements XPackPlugin.XPackPersistentTaskParams { /** TODO Remove in 7.0.0 */ public static final ParseField IGNORE_DOWNTIME = new ParseField("ignore_downtime"); @@ -241,6 +241,11 @@ public boolean equals(Object obj) { public String toString() { return Strings.toString(this); } + + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } } public static class Response extends AcknowledgedResponse { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/action/StartDatafeedAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/action/StartDatafeedAction.java index cd37354f42e4d..df23fb00c89f3 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/action/StartDatafeedAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ml/action/StartDatafeedAction.java @@ -6,6 +6,7 @@ package org.elasticsearch.xpack.core.ml.action; import org.elasticsearch.ElasticsearchParseException; +import org.elasticsearch.Version; import org.elasticsearch.action.Action; import org.elasticsearch.action.ActionRequestBuilder; import org.elasticsearch.action.ActionRequestValidationException; @@ -24,10 +25,10 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.index.mapper.DateFieldMapper; +import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.ml.datafeed.DatafeedConfig; import org.elasticsearch.xpack.core.ml.job.messages.Messages; import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper; -import org.elasticsearch.persistent.PersistentTaskParams; import java.io.IOException; import java.util.Objects; @@ -144,7 +145,7 @@ public boolean equals(Object obj) { } } - public static class DatafeedParams implements PersistentTaskParams { + public static class DatafeedParams implements XPackPlugin.XPackPersistentTaskParams { public static ObjectParser PARSER = new ObjectParser<>(TASK_NAME, DatafeedParams::new); @@ -237,6 +238,11 @@ public String getWriteableName() { return TASK_NAME; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } + @Override public void writeTo(StreamOutput out) throws IOException { out.writeString(datafeedId); diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/job/RollupJob.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/job/RollupJob.java index e71186b60e020..7afcdb71b11cc 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/job/RollupJob.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/job/RollupJob.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.xpack.core.rollup.job; +import org.elasticsearch.Version; import org.elasticsearch.cluster.AbstractDiffable; import org.elasticsearch.cluster.Diff; import org.elasticsearch.common.ParseField; @@ -13,7 +14,7 @@ import org.elasticsearch.common.xcontent.ConstructingObjectParser; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; -import org.elasticsearch.persistent.PersistentTaskParams; +import org.elasticsearch.xpack.core.XPackPlugin; import java.io.IOException; import java.util.Collections; @@ -25,7 +26,7 @@ * It holds the config (RollupJobConfig) and a map of authentication headers. Only RollupJobConfig * is ever serialized to the user, so the headers should never leak */ -public class RollupJob extends AbstractDiffable implements PersistentTaskParams { +public class RollupJob extends AbstractDiffable implements XPackPlugin.XPackPersistentTaskParams { public static final String NAME = "xpack/rollup/job"; @@ -110,4 +111,9 @@ public boolean equals(Object other) { public int hashCode() { return Objects.hash(config, headers); } + + @Override + public Version getMinimalSupportedVersion() { + return Version.V_6_3_0; + } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/WatcherMetaData.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/WatcherMetaData.java index 9f014dee843c5..bddeb5f5e3281 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/WatcherMetaData.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/watcher/WatcherMetaData.java @@ -5,6 +5,7 @@ */ package org.elasticsearch.xpack.core.watcher; +import org.elasticsearch.Version; import org.elasticsearch.cluster.AbstractNamedDiffable; import org.elasticsearch.cluster.NamedDiff; import org.elasticsearch.cluster.metadata.MetaData; @@ -38,6 +39,11 @@ public String getWriteableName() { return TYPE; } + @Override + public Version getMinimalSupportedVersion() { + return Version.CURRENT.minimumCompatibilityVersion(); + } + @Override public EnumSet context() { return EnumSet.of(MetaData.XContentContext.GATEWAY); From 5be554f9066fa18097d74b63e7501d24cbdf6296 Mon Sep 17 00:00:00 2001 From: Boaz Leskes Date: Sun, 3 Jun 2018 21:55:34 +0200 Subject: [PATCH 09/21] Adapt bwc versions after backporting #31045 to 6.x --- .../persistent/PersistentTasksCustomMetaData.java | 4 ++-- .../elasticsearch/persistent/StartPersistentTaskAction.java | 4 ++-- .../test/java/org/elasticsearch/cluster/ClusterStateIT.java | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java index 4b1ba3e11e372..3dc9d6e15ec2d 100644 --- a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java +++ b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java @@ -313,7 +313,7 @@ public PersistentTask(StreamInput in) throws IOException { id = in.readString(); allocationId = in.readLong(); taskName = in.readString(); - if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + if (in.getVersion().onOrAfter(Version.V_6_4_0)) { params = (P) in.readNamedWriteable(PersistentTaskParams.class); } else { params = (P) in.readOptionalNamedWriteable(PersistentTaskParams.class); @@ -328,7 +328,7 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(id); out.writeLong(allocationId); out.writeString(taskName); - if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + if (out.getVersion().onOrAfter(Version.V_6_4_0)) { out.writeNamedWriteable(params); } else { out.writeOptionalNamedWriteable(params); diff --git a/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java b/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java index d2ebf7abbe737..2f78b5740f4ce 100644 --- a/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java +++ b/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java @@ -93,7 +93,7 @@ public void readFrom(StreamInput in) throws IOException { super.readFrom(in); taskId = in.readString(); taskName = in.readString(); - if (in.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + if (in.getVersion().onOrAfter(Version.V_6_4_0)) { params = in.readNamedWriteable(PersistentTaskParams.class); } else { params = in.readOptionalNamedWriteable(PersistentTaskParams.class); @@ -105,7 +105,7 @@ public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); out.writeString(taskId); out.writeString(taskName); - if (out.getVersion().onOrAfter(Version.V_7_0_0_alpha1)) { + if (out.getVersion().onOrAfter(Version.V_6_4_0)) { out.writeNamedWriteable(params); } else { out.writeOptionalNamedWriteable(params); diff --git a/server/src/test/java/org/elasticsearch/cluster/ClusterStateIT.java b/server/src/test/java/org/elasticsearch/cluster/ClusterStateIT.java index 2bf56e888148d..fc917d60deede 100644 --- a/server/src/test/java/org/elasticsearch/cluster/ClusterStateIT.java +++ b/server/src/test/java/org/elasticsearch/cluster/ClusterStateIT.java @@ -33,7 +33,6 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.io.stream.Writeable; -import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; @@ -43,7 +42,6 @@ import org.elasticsearch.script.ScriptService; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.transport.TcpTransport; import org.elasticsearch.watcher.ResourceWatcherService; import java.io.IOException; From 9548c537946d59409fa8e39f581028d556857f68 Mon Sep 17 00:00:00 2001 From: Sohaib Iftikhar Date: Mon, 4 Jun 2018 10:34:55 +0200 Subject: [PATCH 10/21] Move pipeline APIs to ingest namespace (#31027) --- .../elasticsearch/client/ClusterClient.java | 73 ----- .../elasticsearch/client/IngestClient.java | 114 +++++++ .../client/RestHighLevelClient.java | 10 + .../elasticsearch/client/ClusterClientIT.java | 57 ---- .../elasticsearch/client/IngestClientIT.java | 83 ++++++ .../ClusterClientDocumentationIT.java | 216 -------------- .../IngestClientDocumentationIT.java | 279 ++++++++++++++++++ .../delete_pipeline.asciidoc | 24 +- .../{cluster => ingest}/get_pipeline.asciidoc | 22 +- .../{cluster => ingest}/put_pipeline.asciidoc | 24 +- .../high-level/supported-apis.asciidoc | 17 +- 11 files changed, 532 insertions(+), 387 deletions(-) create mode 100644 client/rest-high-level/src/main/java/org/elasticsearch/client/IngestClient.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/IngestClientIT.java create mode 100644 client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IngestClientDocumentationIT.java rename docs/java-rest/high-level/{cluster => ingest}/delete_pipeline.asciidoc (75%) rename docs/java-rest/high-level/{cluster => ingest}/get_pipeline.asciidoc (76%) rename docs/java-rest/high-level/{cluster => ingest}/put_pipeline.asciidoc (77%) diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/ClusterClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/ClusterClient.java index 4254b132b5776..f3c84db79d65f 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/ClusterClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/ClusterClient.java @@ -23,11 +23,6 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse; -import org.elasticsearch.action.ingest.PutPipelineRequest; -import org.elasticsearch.action.ingest.GetPipelineRequest; -import org.elasticsearch.action.ingest.GetPipelineResponse; -import org.elasticsearch.action.ingest.DeletePipelineRequest; -import org.elasticsearch.action.ingest.WritePipelineResponse; import java.io.IOException; @@ -68,72 +63,4 @@ public void putSettingsAsync(ClusterUpdateSettingsRequest clusterUpdateSettingsR restHighLevelClient.performRequestAsyncAndParseEntity(clusterUpdateSettingsRequest, RequestConverters::clusterPutSettings, ClusterUpdateSettingsResponse::fromXContent, listener, emptySet(), headers); } - - /** - * Add a pipeline or update an existing pipeline in the cluster - *

- * See - * Put Pipeline API on elastic.co - */ - public WritePipelineResponse putPipeline(PutPipelineRequest request, Header... headers) throws IOException { - return restHighLevelClient.performRequestAndParseEntity( request, RequestConverters::putPipeline, - WritePipelineResponse::fromXContent, emptySet(), headers); - } - - /** - * Asynchronously add a pipeline or update an existing pipeline in the cluster - *

- * See - * Put Pipeline API on elastic.co - */ - public void putPipelineAsync(PutPipelineRequest request, ActionListener listener, Header... headers) { - restHighLevelClient.performRequestAsyncAndParseEntity( request, RequestConverters::putPipeline, - WritePipelineResponse::fromXContent, listener, emptySet(), headers); - } - - /** - * Get an existing pipeline - *

- * See - * Get Pipeline API on elastic.co - */ - public GetPipelineResponse getPipeline(GetPipelineRequest request, Header... headers) throws IOException { - return restHighLevelClient.performRequestAndParseEntity( request, RequestConverters::getPipeline, - GetPipelineResponse::fromXContent, emptySet(), headers); - } - - /** - * Asynchronously get an existing pipeline - *

- * See - * Get Pipeline API on elastic.co - */ - public void getPipelineAsync(GetPipelineRequest request, ActionListener listener, Header... headers) { - restHighLevelClient.performRequestAsyncAndParseEntity( request, RequestConverters::getPipeline, - GetPipelineResponse::fromXContent, listener, emptySet(), headers); - } - - /** - * Delete an existing pipeline - *

- * See - * - * Delete Pipeline API on elastic.co - */ - public WritePipelineResponse deletePipeline(DeletePipelineRequest request, Header... headers) throws IOException { - return restHighLevelClient.performRequestAndParseEntity( request, RequestConverters::deletePipeline, - WritePipelineResponse::fromXContent, emptySet(), headers); - } - - /** - * Asynchronously delete an existing pipeline - *

- * See - * - * Delete Pipeline API on elastic.co - */ - public void deletePipelineAsync(DeletePipelineRequest request, ActionListener listener, Header... headers) { - restHighLevelClient.performRequestAsyncAndParseEntity( request, RequestConverters::deletePipeline, - WritePipelineResponse::fromXContent, listener, emptySet(), headers); - } } diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/IngestClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/IngestClient.java new file mode 100644 index 0000000000000..72b1813f93909 --- /dev/null +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/IngestClient.java @@ -0,0 +1,114 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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 org.elasticsearch.client; + +import org.apache.http.Header; +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ingest.DeletePipelineRequest; +import org.elasticsearch.action.ingest.GetPipelineRequest; +import org.elasticsearch.action.ingest.GetPipelineResponse; +import org.elasticsearch.action.ingest.PutPipelineRequest; +import org.elasticsearch.action.ingest.WritePipelineResponse; + +import java.io.IOException; + +import static java.util.Collections.emptySet; + +/** + * A wrapper for the {@link RestHighLevelClient} that provides methods for accessing the Ingest API. + *

+ * See Ingest API on elastic.co + */ +public final class IngestClient { + + private final RestHighLevelClient restHighLevelClient; + + IngestClient(RestHighLevelClient restHighLevelClient) { + this.restHighLevelClient = restHighLevelClient; + } + + /** + * Add a pipeline or update an existing pipeline + *

+ * See + * Put Pipeline API on elastic.co + */ + public WritePipelineResponse putPipeline(PutPipelineRequest request, Header... headers) throws IOException { + return restHighLevelClient.performRequestAndParseEntity( request, RequestConverters::putPipeline, + WritePipelineResponse::fromXContent, emptySet(), headers); + } + + /** + * Asynchronously add a pipeline or update an existing pipeline + *

+ * See + * Put Pipeline API on elastic.co + */ + public void putPipelineAsync(PutPipelineRequest request, ActionListener listener, Header... headers) { + restHighLevelClient.performRequestAsyncAndParseEntity( request, RequestConverters::putPipeline, + WritePipelineResponse::fromXContent, listener, emptySet(), headers); + } + + /** + * Get an existing pipeline + *

+ * See + * Get Pipeline API on elastic.co + */ + public GetPipelineResponse getPipeline(GetPipelineRequest request, Header... headers) throws IOException { + return restHighLevelClient.performRequestAndParseEntity( request, RequestConverters::getPipeline, + GetPipelineResponse::fromXContent, emptySet(), headers); + } + + /** + * Asynchronously get an existing pipeline + *

+ * See + * Get Pipeline API on elastic.co + */ + public void getPipelineAsync(GetPipelineRequest request, ActionListener listener, Header... headers) { + restHighLevelClient.performRequestAsyncAndParseEntity( request, RequestConverters::getPipeline, + GetPipelineResponse::fromXContent, listener, emptySet(), headers); + } + + /** + * Delete an existing pipeline + *

+ * See + * + * Delete Pipeline API on elastic.co + */ + public WritePipelineResponse deletePipeline(DeletePipelineRequest request, Header... headers) throws IOException { + return restHighLevelClient.performRequestAndParseEntity( request, RequestConverters::deletePipeline, + WritePipelineResponse::fromXContent, emptySet(), headers); + } + + /** + * Asynchronously delete an existing pipeline + *

+ * See + * + * Delete Pipeline API on elastic.co + */ + public void deletePipelineAsync(DeletePipelineRequest request, ActionListener listener, Header... headers) { + restHighLevelClient.performRequestAsyncAndParseEntity( request, RequestConverters::deletePipeline, + WritePipelineResponse::fromXContent, listener, emptySet(), headers); + } +} diff --git a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java index fc74a43dd8038..a9587b73c1959 100644 --- a/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java +++ b/client/rest-high-level/src/main/java/org/elasticsearch/client/RestHighLevelClient.java @@ -191,6 +191,7 @@ public class RestHighLevelClient implements Closeable { private final IndicesClient indicesClient = new IndicesClient(this); private final ClusterClient clusterClient = new ClusterClient(this); + private final IngestClient ingestClient = new IngestClient(this); private final SnapshotClient snapshotClient = new SnapshotClient(this); private final TasksClient tasksClient = new TasksClient(this); @@ -256,6 +257,15 @@ public final ClusterClient cluster() { return clusterClient; } + /** + * Provides a {@link IngestClient} which can be used to access the Ingest API. + * + * See Ingest API on elastic.co + */ + public final IngestClient ingest() { + return ingestClient; + } + /** * Provides a {@link SnapshotClient} which can be used to access the Snapshot API. * diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/ClusterClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/ClusterClientIT.java index 42db51e81b74d..9314bb2e36cea 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/ClusterClientIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/ClusterClientIT.java @@ -22,20 +22,12 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsRequest; import org.elasticsearch.action.admin.cluster.settings.ClusterUpdateSettingsResponse; -import org.elasticsearch.action.ingest.GetPipelineRequest; -import org.elasticsearch.action.ingest.GetPipelineResponse; -import org.elasticsearch.action.ingest.PutPipelineRequest; -import org.elasticsearch.action.ingest.DeletePipelineRequest; -import org.elasticsearch.action.ingest.WritePipelineResponse; import org.elasticsearch.cluster.routing.allocation.decider.EnableAllocationDecider; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.ByteSizeUnit; -import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.support.XContentMapValues; import org.elasticsearch.indices.recovery.RecoverySettings; -import org.elasticsearch.ingest.PipelineConfiguration; import org.elasticsearch.rest.RestStatus; import java.io.IOException; @@ -113,53 +105,4 @@ public void testClusterUpdateSettingNonExistent() { assertThat(exception.getMessage(), equalTo( "Elasticsearch exception [type=illegal_argument_exception, reason=transient setting [" + setting + "], not recognized]")); } - - public void testPutPipeline() throws IOException { - String id = "some_pipeline_id"; - XContentBuilder pipelineBuilder = buildRandomXContentPipeline(); - PutPipelineRequest request = new PutPipelineRequest( - id, - BytesReference.bytes(pipelineBuilder), - pipelineBuilder.contentType()); - - WritePipelineResponse putPipelineResponse = - execute(request, highLevelClient().cluster()::putPipeline, highLevelClient().cluster()::putPipelineAsync); - assertTrue(putPipelineResponse.isAcknowledged()); - } - - public void testGetPipeline() throws IOException { - String id = "some_pipeline_id"; - XContentBuilder pipelineBuilder = buildRandomXContentPipeline(); - { - PutPipelineRequest request = new PutPipelineRequest( - id, - BytesReference.bytes(pipelineBuilder), - pipelineBuilder.contentType() - ); - createPipeline(request); - } - - GetPipelineRequest request = new GetPipelineRequest(id); - - GetPipelineResponse response = - execute(request, highLevelClient().cluster()::getPipeline, highLevelClient().cluster()::getPipelineAsync); - assertTrue(response.isFound()); - assertEquals(response.pipelines().get(0).getId(), id); - PipelineConfiguration expectedConfig = - new PipelineConfiguration(id, BytesReference.bytes(pipelineBuilder), pipelineBuilder.contentType()); - assertEquals(expectedConfig.getConfigAsMap(), response.pipelines().get(0).getConfigAsMap()); - } - - public void testDeletePipeline() throws IOException { - String id = "some_pipeline_id"; - { - createPipeline(id); - } - - DeletePipelineRequest request = new DeletePipelineRequest(id); - - WritePipelineResponse response = - execute(request, highLevelClient().cluster()::deletePipeline, highLevelClient().cluster()::deletePipelineAsync); - assertTrue(response.isAcknowledged()); - } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/IngestClientIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/IngestClientIT.java new file mode 100644 index 0000000000000..ecc0d0052d415 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/IngestClientIT.java @@ -0,0 +1,83 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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 org.elasticsearch.client; + +import org.elasticsearch.action.ingest.DeletePipelineRequest; +import org.elasticsearch.action.ingest.GetPipelineRequest; +import org.elasticsearch.action.ingest.GetPipelineResponse; +import org.elasticsearch.action.ingest.PutPipelineRequest; +import org.elasticsearch.action.ingest.WritePipelineResponse; +import org.elasticsearch.common.bytes.BytesReference; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.ingest.PipelineConfiguration; + +import java.io.IOException; + +public class IngestClientIT extends ESRestHighLevelClientTestCase { + + public void testPutPipeline() throws IOException { + String id = "some_pipeline_id"; + XContentBuilder pipelineBuilder = buildRandomXContentPipeline(); + PutPipelineRequest request = new PutPipelineRequest( + id, + BytesReference.bytes(pipelineBuilder), + pipelineBuilder.contentType()); + + WritePipelineResponse putPipelineResponse = + execute(request, highLevelClient().ingest()::putPipeline, highLevelClient().ingest()::putPipelineAsync); + assertTrue(putPipelineResponse.isAcknowledged()); + } + + public void testGetPipeline() throws IOException { + String id = "some_pipeline_id"; + XContentBuilder pipelineBuilder = buildRandomXContentPipeline(); + { + PutPipelineRequest request = new PutPipelineRequest( + id, + BytesReference.bytes(pipelineBuilder), + pipelineBuilder.contentType() + ); + createPipeline(request); + } + + GetPipelineRequest request = new GetPipelineRequest(id); + + GetPipelineResponse response = + execute(request, highLevelClient().ingest()::getPipeline, highLevelClient().ingest()::getPipelineAsync); + assertTrue(response.isFound()); + assertEquals(response.pipelines().get(0).getId(), id); + PipelineConfiguration expectedConfig = + new PipelineConfiguration(id, BytesReference.bytes(pipelineBuilder), pipelineBuilder.contentType()); + assertEquals(expectedConfig.getConfigAsMap(), response.pipelines().get(0).getConfigAsMap()); + } + + public void testDeletePipeline() throws IOException { + String id = "some_pipeline_id"; + { + createPipeline(id); + } + + DeletePipelineRequest request = new DeletePipelineRequest(id); + + WritePipelineResponse response = + execute(request, highLevelClient().ingest()::deletePipeline, highLevelClient().ingest()::deletePipelineAsync); + assertTrue(response.isAcknowledged()); + } +} diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/ClusterClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/ClusterClientDocumentationIT.java index 0da577f17e873..304c5010a47e3 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/ClusterClientDocumentationIT.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/ClusterClientDocumentationIT.java @@ -186,220 +186,4 @@ public void onFailure(Exception e) { assertTrue(latch.await(30L, TimeUnit.SECONDS)); } } - - public void testPutPipeline() throws IOException { - RestHighLevelClient client = highLevelClient(); - - { - // tag::put-pipeline-request - String source = - "{\"description\":\"my set of processors\"," + - "\"processors\":[{\"set\":{\"field\":\"foo\",\"value\":\"bar\"}}]}"; - PutPipelineRequest request = new PutPipelineRequest( - "my-pipeline-id", // <1> - new BytesArray(source.getBytes(StandardCharsets.UTF_8)), // <2> - XContentType.JSON // <3> - ); - // end::put-pipeline-request - - // tag::put-pipeline-request-timeout - request.timeout(TimeValue.timeValueMinutes(2)); // <1> - request.timeout("2m"); // <2> - // end::put-pipeline-request-timeout - - // tag::put-pipeline-request-masterTimeout - request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> - request.masterNodeTimeout("1m"); // <2> - // end::put-pipeline-request-masterTimeout - - // tag::put-pipeline-execute - WritePipelineResponse response = client.cluster().putPipeline(request); // <1> - // end::put-pipeline-execute - - // tag::put-pipeline-response - boolean acknowledged = response.isAcknowledged(); // <1> - // end::put-pipeline-response - assertTrue(acknowledged); - } - } - - public void testPutPipelineAsync() throws Exception { - RestHighLevelClient client = highLevelClient(); - - { - String source = - "{\"description\":\"my set of processors\"," + - "\"processors\":[{\"set\":{\"field\":\"foo\",\"value\":\"bar\"}}]}"; - PutPipelineRequest request = new PutPipelineRequest( - "my-pipeline-id", - new BytesArray(source.getBytes(StandardCharsets.UTF_8)), - XContentType.JSON - ); - - // tag::put-pipeline-execute-listener - ActionListener listener = - new ActionListener() { - @Override - public void onResponse(WritePipelineResponse response) { - // <1> - } - - @Override - public void onFailure(Exception e) { - // <2> - } - }; - // end::put-pipeline-execute-listener - - // Replace the empty listener by a blocking listener in test - final CountDownLatch latch = new CountDownLatch(1); - listener = new LatchedActionListener<>(listener, latch); - - // tag::put-pipeline-execute-async - client.cluster().putPipelineAsync(request, listener); // <1> - // end::put-pipeline-execute-async - - assertTrue(latch.await(30L, TimeUnit.SECONDS)); - } - } - - public void testGetPipeline() throws IOException { - RestHighLevelClient client = highLevelClient(); - - { - createPipeline("my-pipeline-id"); - } - - { - // tag::get-pipeline-request - GetPipelineRequest request = new GetPipelineRequest("my-pipeline-id"); // <1> - // end::get-pipeline-request - - // tag::get-pipeline-request-masterTimeout - request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> - request.masterNodeTimeout("1m"); // <2> - // end::get-pipeline-request-masterTimeout - - // tag::get-pipeline-execute - GetPipelineResponse response = client.cluster().getPipeline(request); // <1> - // end::get-pipeline-execute - - // tag::get-pipeline-response - boolean successful = response.isFound(); // <1> - List pipelines = response.pipelines(); // <2> - for(PipelineConfiguration pipeline: pipelines) { - Map config = pipeline.getConfigAsMap(); // <3> - } - // end::get-pipeline-response - - assertTrue(successful); - } - } - - public void testGetPipelineAsync() throws Exception { - RestHighLevelClient client = highLevelClient(); - - { - createPipeline("my-pipeline-id"); - } - - { - GetPipelineRequest request = new GetPipelineRequest("my-pipeline-id"); - - // tag::get-pipeline-execute-listener - ActionListener listener = - new ActionListener() { - @Override - public void onResponse(GetPipelineResponse response) { - // <1> - } - - @Override - public void onFailure(Exception e) { - // <2> - } - }; - // end::get-pipeline-execute-listener - - // Replace the empty listener by a blocking listener in test - final CountDownLatch latch = new CountDownLatch(1); - listener = new LatchedActionListener<>(listener, latch); - - // tag::get-pipeline-execute-async - client.cluster().getPipelineAsync(request, listener); // <1> - // end::get-pipeline-execute-async - - assertTrue(latch.await(30L, TimeUnit.SECONDS)); - } - } - - public void testDeletePipeline() throws IOException { - RestHighLevelClient client = highLevelClient(); - - { - createPipeline("my-pipeline-id"); - } - - { - // tag::delete-pipeline-request - DeletePipelineRequest request = new DeletePipelineRequest("my-pipeline-id"); // <1> - // end::delete-pipeline-request - - // tag::delete-pipeline-request-timeout - request.timeout(TimeValue.timeValueMinutes(2)); // <1> - request.timeout("2m"); // <2> - // end::delete-pipeline-request-timeout - - // tag::delete-pipeline-request-masterTimeout - request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> - request.masterNodeTimeout("1m"); // <2> - // end::delete-pipeline-request-masterTimeout - - // tag::delete-pipeline-execute - WritePipelineResponse response = client.cluster().deletePipeline(request); // <1> - // end::delete-pipeline-execute - - // tag::delete-pipeline-response - boolean acknowledged = response.isAcknowledged(); // <1> - // end::delete-pipeline-response - assertTrue(acknowledged); - } - } - - public void testDeletePipelineAsync() throws Exception { - RestHighLevelClient client = highLevelClient(); - - { - createPipeline("my-pipeline-id"); - } - - { - DeletePipelineRequest request = new DeletePipelineRequest("my-pipeline-id"); - - // tag::delete-pipeline-execute-listener - ActionListener listener = - new ActionListener() { - @Override - public void onResponse(WritePipelineResponse response) { - // <1> - } - - @Override - public void onFailure(Exception e) { - // <2> - } - }; - // end::delete-pipeline-execute-listener - - // Replace the empty listener by a blocking listener in test - final CountDownLatch latch = new CountDownLatch(1); - listener = new LatchedActionListener<>(listener, latch); - - // tag::delete-pipeline-execute-async - client.cluster().deletePipelineAsync(request, listener); // <1> - // end::delete-pipeline-execute-async - - assertTrue(latch.await(30L, TimeUnit.SECONDS)); - } - } } diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IngestClientDocumentationIT.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IngestClientDocumentationIT.java new file mode 100644 index 0000000000000..7971e49da44f4 --- /dev/null +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/IngestClientDocumentationIT.java @@ -0,0 +1,279 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch 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 org.elasticsearch.client.documentation; + +import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.LatchedActionListener; +import org.elasticsearch.action.ingest.DeletePipelineRequest; +import org.elasticsearch.action.ingest.GetPipelineRequest; +import org.elasticsearch.action.ingest.GetPipelineResponse; +import org.elasticsearch.action.ingest.PutPipelineRequest; +import org.elasticsearch.action.ingest.WritePipelineResponse; +import org.elasticsearch.client.ESRestHighLevelClientTestCase; +import org.elasticsearch.client.RestHighLevelClient; +import org.elasticsearch.common.bytes.BytesArray; +import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.ingest.PipelineConfiguration; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * This class is used to generate the Java Ingest API documentation. + * You need to wrap your code between two tags like: + * // tag::example + * // end::example + * + * Where example is your tag name. + * + * Then in the documentation, you can extract what is between tag and end tags with + * ["source","java",subs="attributes,callouts,macros"] + * -------------------------------------------------- + * include-tagged::{doc-tests}/IngestClientDocumentationIT.java[example] + * -------------------------------------------------- + * + * The column width of the code block is 84. If the code contains a line longer + * than 84, the line will be cut and a horizontal scroll bar will be displayed. + * (the code indentation of the tag is not included in the width) + */ +public class IngestClientDocumentationIT extends ESRestHighLevelClientTestCase { + + public void testPutPipeline() throws IOException { + RestHighLevelClient client = highLevelClient(); + + { + // tag::put-pipeline-request + String source = + "{\"description\":\"my set of processors\"," + + "\"processors\":[{\"set\":{\"field\":\"foo\",\"value\":\"bar\"}}]}"; + PutPipelineRequest request = new PutPipelineRequest( + "my-pipeline-id", // <1> + new BytesArray(source.getBytes(StandardCharsets.UTF_8)), // <2> + XContentType.JSON // <3> + ); + // end::put-pipeline-request + + // tag::put-pipeline-request-timeout + request.timeout(TimeValue.timeValueMinutes(2)); // <1> + request.timeout("2m"); // <2> + // end::put-pipeline-request-timeout + + // tag::put-pipeline-request-masterTimeout + request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> + request.masterNodeTimeout("1m"); // <2> + // end::put-pipeline-request-masterTimeout + + // tag::put-pipeline-execute + WritePipelineResponse response = client.ingest().putPipeline(request); // <1> + // end::put-pipeline-execute + + // tag::put-pipeline-response + boolean acknowledged = response.isAcknowledged(); // <1> + // end::put-pipeline-response + assertTrue(acknowledged); + } + } + + public void testPutPipelineAsync() throws Exception { + RestHighLevelClient client = highLevelClient(); + + { + String source = + "{\"description\":\"my set of processors\"," + + "\"processors\":[{\"set\":{\"field\":\"foo\",\"value\":\"bar\"}}]}"; + PutPipelineRequest request = new PutPipelineRequest( + "my-pipeline-id", + new BytesArray(source.getBytes(StandardCharsets.UTF_8)), + XContentType.JSON + ); + + // tag::put-pipeline-execute-listener + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(WritePipelineResponse response) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::put-pipeline-execute-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::put-pipeline-execute-async + client.ingest().putPipelineAsync(request, listener); // <1> + // end::put-pipeline-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } + } + + public void testGetPipeline() throws IOException { + RestHighLevelClient client = highLevelClient(); + + { + createPipeline("my-pipeline-id"); + } + + { + // tag::get-pipeline-request + GetPipelineRequest request = new GetPipelineRequest("my-pipeline-id"); // <1> + // end::get-pipeline-request + + // tag::get-pipeline-request-masterTimeout + request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> + request.masterNodeTimeout("1m"); // <2> + // end::get-pipeline-request-masterTimeout + + // tag::get-pipeline-execute + GetPipelineResponse response = client.ingest().getPipeline(request); // <1> + // end::get-pipeline-execute + + // tag::get-pipeline-response + boolean successful = response.isFound(); // <1> + List pipelines = response.pipelines(); // <2> + for(PipelineConfiguration pipeline: pipelines) { + Map config = pipeline.getConfigAsMap(); // <3> + } + // end::get-pipeline-response + + assertTrue(successful); + } + } + + public void testGetPipelineAsync() throws Exception { + RestHighLevelClient client = highLevelClient(); + + { + createPipeline("my-pipeline-id"); + } + + { + GetPipelineRequest request = new GetPipelineRequest("my-pipeline-id"); + + // tag::get-pipeline-execute-listener + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(GetPipelineResponse response) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::get-pipeline-execute-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::get-pipeline-execute-async + client.ingest().getPipelineAsync(request, listener); // <1> + // end::get-pipeline-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } + } + + public void testDeletePipeline() throws IOException { + RestHighLevelClient client = highLevelClient(); + + { + createPipeline("my-pipeline-id"); + } + + { + // tag::delete-pipeline-request + DeletePipelineRequest request = new DeletePipelineRequest("my-pipeline-id"); // <1> + // end::delete-pipeline-request + + // tag::delete-pipeline-request-timeout + request.timeout(TimeValue.timeValueMinutes(2)); // <1> + request.timeout("2m"); // <2> + // end::delete-pipeline-request-timeout + + // tag::delete-pipeline-request-masterTimeout + request.masterNodeTimeout(TimeValue.timeValueMinutes(1)); // <1> + request.masterNodeTimeout("1m"); // <2> + // end::delete-pipeline-request-masterTimeout + + // tag::delete-pipeline-execute + WritePipelineResponse response = client.ingest().deletePipeline(request); // <1> + // end::delete-pipeline-execute + + // tag::delete-pipeline-response + boolean acknowledged = response.isAcknowledged(); // <1> + // end::delete-pipeline-response + assertTrue(acknowledged); + } + } + + public void testDeletePipelineAsync() throws Exception { + RestHighLevelClient client = highLevelClient(); + + { + createPipeline("my-pipeline-id"); + } + + { + DeletePipelineRequest request = new DeletePipelineRequest("my-pipeline-id"); + + // tag::delete-pipeline-execute-listener + ActionListener listener = + new ActionListener() { + @Override + public void onResponse(WritePipelineResponse response) { + // <1> + } + + @Override + public void onFailure(Exception e) { + // <2> + } + }; + // end::delete-pipeline-execute-listener + + // Replace the empty listener by a blocking listener in test + final CountDownLatch latch = new CountDownLatch(1); + listener = new LatchedActionListener<>(listener, latch); + + // tag::delete-pipeline-execute-async + client.ingest().deletePipelineAsync(request, listener); // <1> + // end::delete-pipeline-execute-async + + assertTrue(latch.await(30L, TimeUnit.SECONDS)); + } + } + +} diff --git a/docs/java-rest/high-level/cluster/delete_pipeline.asciidoc b/docs/java-rest/high-level/ingest/delete_pipeline.asciidoc similarity index 75% rename from docs/java-rest/high-level/cluster/delete_pipeline.asciidoc rename to docs/java-rest/high-level/ingest/delete_pipeline.asciidoc index f809f831f7814..3801f8a3b5280 100644 --- a/docs/java-rest/high-level/cluster/delete_pipeline.asciidoc +++ b/docs/java-rest/high-level/ingest/delete_pipeline.asciidoc @@ -1,14 +1,14 @@ -[[java-rest-high-cluster-delete-pipeline]] +[[java-rest-high-ingest-delete-pipeline]] === Delete Pipeline API -[[java-rest-high-cluster-delete-pipeline-request]] +[[java-rest-high-ingest-delete-pipeline-request]] ==== Delete Pipeline Request A `DeletePipelineRequest` requires a pipeline `id` to delete. ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[delete-pipeline-request] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[delete-pipeline-request] -------------------------------------------------- <1> The pipeline id to delete @@ -17,28 +17,28 @@ The following arguments can optionally be provided: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[delete-pipeline-request-timeout] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[delete-pipeline-request-timeout] -------------------------------------------------- <1> Timeout to wait for the all the nodes to acknowledge the pipeline deletion as a `TimeValue` <2> Timeout to wait for the all the nodes to acknowledge the pipeline deletion as a `String` ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[delete-pipeline-request-masterTimeout] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[delete-pipeline-request-masterTimeout] -------------------------------------------------- <1> Timeout to connect to the master node as a `TimeValue` <2> Timeout to connect to the master node as a `String` -[[java-rest-high-cluster-delete-pipeline-sync]] +[[java-rest-high-ingest-delete-pipeline-sync]] ==== Synchronous Execution ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[delete-pipeline-execute] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[delete-pipeline-execute] -------------------------------------------------- <1> Execute the request and get back the response in a `WritePipelineResponse` object. -[[java-rest-high-cluster-delete-pipeline-async]] +[[java-rest-high-ingest-delete-pipeline-async]] ==== Asynchronous Execution The asynchronous execution of a delete pipeline request requires both the `DeletePipelineRequest` @@ -47,7 +47,7 @@ method: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[delete-pipeline-execute-async] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[delete-pipeline-execute-async] -------------------------------------------------- <1> The `DeletePipelineRequest` to execute and the `ActionListener` to use when the execution completes @@ -61,13 +61,13 @@ A typical listener for `WritePipelineResponse` looks like: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[delete-pipeline-execute-listener] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[delete-pipeline-execute-listener] -------------------------------------------------- <1> Called when the execution is successfully completed. The response is provided as an argument <2> Called in case of failure. The raised exception is provided as an argument -[[java-rest-high-cluster-delete-pipeline-response]] +[[java-rest-high-ingest-delete-pipeline-response]] ==== Delete Pipeline Response The returned `WritePipelineResponse` allows to retrieve information about the executed @@ -75,6 +75,6 @@ The returned `WritePipelineResponse` allows to retrieve information about the ex ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[delete-pipeline-response] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[delete-pipeline-response] -------------------------------------------------- <1> Indicates whether all of the nodes have acknowledged the request diff --git a/docs/java-rest/high-level/cluster/get_pipeline.asciidoc b/docs/java-rest/high-level/ingest/get_pipeline.asciidoc similarity index 76% rename from docs/java-rest/high-level/cluster/get_pipeline.asciidoc rename to docs/java-rest/high-level/ingest/get_pipeline.asciidoc index d6a9472a715e1..54ba545d70982 100644 --- a/docs/java-rest/high-level/cluster/get_pipeline.asciidoc +++ b/docs/java-rest/high-level/ingest/get_pipeline.asciidoc @@ -1,14 +1,14 @@ -[[java-rest-high-cluster-get-pipeline]] +[[java-rest-high-ingest-get-pipeline]] === Get Pipeline API -[[java-rest-high-cluster-get-pipeline-request]] +[[java-rest-high-ingest-get-pipeline-request]] ==== Get Pipeline Request A `GetPipelineRequest` requires one or more `pipelineIds` to fetch. ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-pipeline-request] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[get-pipeline-request] -------------------------------------------------- <1> The pipeline id to fetch @@ -17,21 +17,21 @@ The following arguments can optionally be provided: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-pipeline-request-masterTimeout] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[get-pipeline-request-masterTimeout] -------------------------------------------------- <1> Timeout to connect to the master node as a `TimeValue` <2> Timeout to connect to the master node as a `String` -[[java-rest-high-cluster-get-pipeline-sync]] +[[java-rest-high-ingest-get-pipeline-sync]] ==== Synchronous Execution ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-pipeline-execute] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[get-pipeline-execute] -------------------------------------------------- <1> Execute the request and get back the response in a GetPipelineResponse object. -[[java-rest-high-cluster-get-pipeline-async]] +[[java-rest-high-ingest-get-pipeline-async]] ==== Asynchronous Execution The asynchronous execution of a get pipeline request requires both the `GetPipelineRequest` @@ -40,7 +40,7 @@ method: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-pipeline-execute-async] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[get-pipeline-execute-async] -------------------------------------------------- <1> The `GetPipelineRequest` to execute and the `ActionListener` to use when the execution completes @@ -54,13 +54,13 @@ A typical listener for `GetPipelineResponse` looks like: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-pipeline-execute-listener] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[get-pipeline-execute-listener] -------------------------------------------------- <1> Called when the execution is successfully completed. The response is provided as an argument <2> Called in case of failure. The raised exception is provided as an argument -[[java-rest-high-cluster-get-pipeline-response]] +[[java-rest-high-ingest-get-pipeline-response]] ==== Get Pipeline Response The returned `GetPipelineResponse` allows to retrieve information about the executed @@ -68,7 +68,7 @@ The returned `GetPipelineResponse` allows to retrieve information about the exec ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[get-pipeline-response] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[get-pipeline-response] -------------------------------------------------- <1> Check if a matching pipeline id was found or not. <2> Get the list of pipelines found as a list of `PipelineConfig` objects. diff --git a/docs/java-rest/high-level/cluster/put_pipeline.asciidoc b/docs/java-rest/high-level/ingest/put_pipeline.asciidoc similarity index 77% rename from docs/java-rest/high-level/cluster/put_pipeline.asciidoc rename to docs/java-rest/high-level/ingest/put_pipeline.asciidoc index 942b75b74cd0b..12a4eb15bce65 100644 --- a/docs/java-rest/high-level/cluster/put_pipeline.asciidoc +++ b/docs/java-rest/high-level/ingest/put_pipeline.asciidoc @@ -1,7 +1,7 @@ -[[java-rest-high-cluster-put-pipeline]] +[[java-rest-high-ingest-put-pipeline]] === Put Pipeline API -[[java-rest-high-cluster-put-pipeline-request]] +[[java-rest-high-ingest-put-pipeline-request]] ==== Put Pipeline Request A `PutPipelineRequest` requires an `id` argument, a source and a `XContentType`. The source consists @@ -9,7 +9,7 @@ of a description and a list of `Processor` objects. ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-pipeline-request] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[put-pipeline-request] -------------------------------------------------- <1> The pipeline id <2> The source for the pipeline as a `ByteArray`. @@ -20,28 +20,28 @@ The following arguments can optionally be provided: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-pipeline-request-timeout] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[put-pipeline-request-timeout] -------------------------------------------------- <1> Timeout to wait for the all the nodes to acknowledge the pipeline creation as a `TimeValue` <2> Timeout to wait for the all the nodes to acknowledge the pipeline creation as a `String` ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-pipeline-request-masterTimeout] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[put-pipeline-request-masterTimeout] -------------------------------------------------- <1> Timeout to connect to the master node as a `TimeValue` <2> Timeout to connect to the master node as a `String` -[[java-rest-high-cluster-put-pipeline-sync]] +[[java-rest-high-ingest-put-pipeline-sync]] ==== Synchronous Execution ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-pipeline-execute] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[put-pipeline-execute] -------------------------------------------------- <1> Execute the request and get back the response in a WritePipelineResponse object. -[[java-rest-high-cluster-put-pipeline-async]] +[[java-rest-high-ingest-put-pipeline-async]] ==== Asynchronous Execution The asynchronous execution of a put pipeline request requires both the `PutPipelineRequest` @@ -50,7 +50,7 @@ method: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-pipeline-execute-async] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[put-pipeline-execute-async] -------------------------------------------------- <1> The `PutPipelineRequest` to execute and the `ActionListener` to use when the execution completes @@ -64,13 +64,13 @@ A typical listener for `WritePipelineResponse` looks like: ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-pipeline-execute-listener] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[put-pipeline-execute-listener] -------------------------------------------------- <1> Called when the execution is successfully completed. The response is provided as an argument <2> Called in case of failure. The raised exception is provided as an argument -[[java-rest-high-cluster-put-pipeline-response]] +[[java-rest-high-ingest-put-pipeline-response]] ==== Put Pipeline Response The returned `WritePipelineResponse` allows to retrieve information about the executed @@ -78,6 +78,6 @@ The returned `WritePipelineResponse` allows to retrieve information about the ex ["source","java",subs="attributes,callouts,macros"] -------------------------------------------------- -include-tagged::{doc-tests}/ClusterClientDocumentationIT.java[put-pipeline-response] +include-tagged::{doc-tests}/IngestClientDocumentationIT.java[put-pipeline-response] -------------------------------------------------- <1> Indicates whether all of the nodes have acknowledged the request diff --git a/docs/java-rest/high-level/supported-apis.asciidoc b/docs/java-rest/high-level/supported-apis.asciidoc index 534d161abc3cf..35d8b8901b4e7 100644 --- a/docs/java-rest/high-level/supported-apis.asciidoc +++ b/docs/java-rest/high-level/supported-apis.asciidoc @@ -106,14 +106,19 @@ include::indices/get_settings.asciidoc[] The Java High Level REST Client supports the following Cluster APIs: * <> -* <> -* <> -* <> include::cluster/put_settings.asciidoc[] -include::cluster/put_pipeline.asciidoc[] -include::cluster/get_pipeline.asciidoc[] -include::cluster/delete_pipeline.asciidoc[] + +== Ingest APIs +The Java High Level REST Client supports the following Ingest APIs: + +* <> +* <> +* <> + +include::ingest/put_pipeline.asciidoc[] +include::ingest/get_pipeline.asciidoc[] +include::ingest/delete_pipeline.asciidoc[] == Snapshot APIs From 9bac2aedd9e275134decb4dbabcae5463690c380 Mon Sep 17 00:00:00 2001 From: Itamar Syn-Hershko Date: Mon, 4 Jun 2018 16:42:29 +0300 Subject: [PATCH 11/21] Remove usage of explicit type in docs (#29667) --- docs/reference/indices/templates.asciidoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/reference/indices/templates.asciidoc b/docs/reference/indices/templates.asciidoc index 6aefe3ccb4744..051e78fc44297 100644 --- a/docs/reference/indices/templates.asciidoc +++ b/docs/reference/indices/templates.asciidoc @@ -23,7 +23,7 @@ PUT _template/template_1 "number_of_shards": 1 }, "mappings": { - "type1": { + "_doc": { "_source": { "enabled": false }, @@ -157,7 +157,7 @@ PUT /_template/template_1 "number_of_shards" : 1 }, "mappings" : { - "type1" : { + "_doc" : { "_source" : { "enabled" : false } } } @@ -171,7 +171,7 @@ PUT /_template/template_2 "number_of_shards" : 1 }, "mappings" : { - "type1" : { + "_doc" : { "_source" : { "enabled" : true } } } @@ -180,7 +180,7 @@ PUT /_template/template_2 // CONSOLE // TEST[s/^/DELETE _template\/template_1\n/] -The above will disable storing the `_source` on all `type1` types, but +The above will disable storing the `_source`, but for indices that start with `te*`, `_source` will still be enabled. Note, for mappings, the merging is "deep", meaning that specific object/property based mappings can easily be added/overridden on higher From b9b7bd4e119586b5d13da869d7ca1e2e5b3e76ff Mon Sep 17 00:00:00 2001 From: Boaz Leskes Date: Sun, 3 Jun 2018 21:55:34 +0200 Subject: [PATCH 12/21] Adapt bwc versions after backporting #31045 to 6.3 --- .../persistent/PersistentTasksCustomMetaData.java | 4 ++-- .../elasticsearch/persistent/StartPersistentTaskAction.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java index 3dc9d6e15ec2d..09346704a801d 100644 --- a/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java +++ b/server/src/main/java/org/elasticsearch/persistent/PersistentTasksCustomMetaData.java @@ -313,7 +313,7 @@ public PersistentTask(StreamInput in) throws IOException { id = in.readString(); allocationId = in.readLong(); taskName = in.readString(); - if (in.getVersion().onOrAfter(Version.V_6_4_0)) { + if (in.getVersion().onOrAfter(Version.V_6_3_0)) { params = (P) in.readNamedWriteable(PersistentTaskParams.class); } else { params = (P) in.readOptionalNamedWriteable(PersistentTaskParams.class); @@ -328,7 +328,7 @@ public void writeTo(StreamOutput out) throws IOException { out.writeString(id); out.writeLong(allocationId); out.writeString(taskName); - if (out.getVersion().onOrAfter(Version.V_6_4_0)) { + if (out.getVersion().onOrAfter(Version.V_6_3_0)) { out.writeNamedWriteable(params); } else { out.writeOptionalNamedWriteable(params); diff --git a/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java b/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java index 2f78b5740f4ce..341fdc5062200 100644 --- a/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java +++ b/server/src/main/java/org/elasticsearch/persistent/StartPersistentTaskAction.java @@ -93,7 +93,7 @@ public void readFrom(StreamInput in) throws IOException { super.readFrom(in); taskId = in.readString(); taskName = in.readString(); - if (in.getVersion().onOrAfter(Version.V_6_4_0)) { + if (in.getVersion().onOrAfter(Version.V_6_3_0)) { params = in.readNamedWriteable(PersistentTaskParams.class); } else { params = in.readOptionalNamedWriteable(PersistentTaskParams.class); @@ -105,7 +105,7 @@ public void writeTo(StreamOutput out) throws IOException { super.writeTo(out); out.writeString(taskId); out.writeString(taskName); - if (out.getVersion().onOrAfter(Version.V_6_4_0)) { + if (out.getVersion().onOrAfter(Version.V_6_3_0)) { out.writeNamedWriteable(params); } else { out.writeOptionalNamedWriteable(params); From b81366f427ecc09fd0f10a74bd7e14608803d8c6 Mon Sep 17 00:00:00 2001 From: Nik Everett Date: Mon, 4 Jun 2018 11:04:22 -0400 Subject: [PATCH 13/21] QA: Check rollup job creation safety (#31036) Prior to #30963 you could create a rollup job that would poison the cluster state for nodes that don't have xpack installed. This adds a test that would have caught that. --- .../org/elasticsearch/upgrades/XPackIT.java | 75 ++++++++++++++++++- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/XPackIT.java b/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/XPackIT.java index b490f941b3571..35d7756e2f4f7 100644 --- a/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/XPackIT.java +++ b/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/XPackIT.java @@ -26,6 +26,7 @@ import org.junit.Before; import org.elasticsearch.Version; import org.elasticsearch.client.Request; +import org.elasticsearch.client.ResponseException; import java.io.IOException; import java.util.ArrayList; @@ -33,6 +34,8 @@ import java.util.List; import java.util.Map; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.junit.Assume.assumeThat; @@ -42,6 +45,11 @@ * cluster is the on the "zip" distribution. */ public class XPackIT extends AbstractRollingTestCase { + private static final Version UPGRADE_FROM_VERSION = + Version.fromString(System.getProperty("tests.upgrade_from_version")); + private static final boolean UPGRADE_FROM_VERSION_HAS_XPACK = + UPGRADE_FROM_VERSION.onOrAfter(Version.V_6_3_0); + @Before public void skipIfNotZip() { assumeThat("test is only supported if the distribution contains xpack", @@ -68,11 +76,8 @@ public void skipIfNotZip() { * system. */ public void testIndexTemplatesCreated() throws Exception { - Version upgradeFromVersion = - Version.fromString(System.getProperty("tests.upgrade_from_version")); - boolean upgradeFromVersionHasXPack = upgradeFromVersion.onOrAfter(Version.V_6_3_0); assumeFalse("this test doesn't really prove anything if the starting version has xpack and it is *much* more complex to maintain", - upgradeFromVersionHasXPack); + UPGRADE_FROM_VERSION_HAS_XPACK); assumeFalse("since we're upgrading from a version without x-pack it won't have any templates", CLUSTER_TYPE == ClusterType.OLD); @@ -193,6 +198,68 @@ public void testTrialLicense() throws IOException { client().performRequest(createJob); } + /** + * Attempts to create a rollup job and validates that the right + * thing happens. If all nodes don't have xpack then it should + * fail, either with a "I don't support this API" message or a + * "the following nodes aren't ready". If all the nodes has xpack + * then it should just work. This would catch issues where rollup + * would pollute the cluster state with its job that the non-xpack + * nodes couldn't understand. + */ + public void testCreateRollup() throws IOException { + // Rollup validates its input on job creation so lets make an index for it + Request indexInputDoc = new Request("POST", "/rollup_test_input_1/doc/"); + indexInputDoc.setJsonEntity( + "{\n" + + " \"timestamp\":\"2018-01-01T00:00:00\",\n" + + " \"node\": \"node1\",\n" + + " \"voltage\": 12.6\n" + + "}"); + client().performRequest(indexInputDoc); + + // Actually attempt the rollup and catch the errors if there should be any + Request createJob = new Request("PUT", "/_xpack/rollup/job/" + System.nanoTime()); + createJob.setJsonEntity( + "{\n" + + " \"index_pattern\" : \"rollup_test_input_*\",\n" + + " \"rollup_index\": \"rollup_test_output\",\n" + + " \"cron\": \"*/30 * * * * ?\",\n" + + " \"page_size\": 1000,\n" + + " \"groups\": {\n" + + " \"date_histogram\": {\n" + + " \"field\": \"timestamp\",\n" + + " \"interval\": \"1h\",\n" + + " \"delay\": \"7d\"\n" + + " },\n" + + " \"terms\": {\n" + + " \"fields\": [\"node.keyword\"]\n" + + " }\n" + + " },\n" + + " \"metrics\": [\n" + + " {\"field\": \"voltage\", \"metrics\": [\"avg\"]}\n" + + " ]\n" + + "}\n"); + if (UPGRADE_FROM_VERSION_HAS_XPACK || CLUSTER_TYPE == ClusterType.UPGRADED) { + client().performRequest(createJob); + } else { + ResponseException e = expectThrows(ResponseException.class, () -> + client().performRequest(createJob)); + assertThat(e.getMessage(), anyOf( + // Request landed on a node without xpack + containsString("No handler found for uri"), + // Request landed on a node *with* xpack but the master doesn't have it + containsString("No handler for action"), + // Request landed on a node *with* xpack and the master has it but other nodes do not + containsString("The following nodes are not ready yet for enabling x-pack custom metadata"))); + } + + // Whether or not there are errors we should be able to modify the cluster state + Request createIndex = new Request("PUT", "/test_index" + System.nanoTime()); + client().performRequest(createIndex); + client().performRequest(new Request("DELETE", createIndex.getEndpoint())); + } + /** * Has the master been upgraded to the new version? */ From c43d19993fcc2ca95a57afbf0728034f338cdb62 Mon Sep 17 00:00:00 2001 From: David Kyle Date: Mon, 4 Jun 2018 16:31:35 +0100 Subject: [PATCH 14/21] [ML] Add secondary sort to ML events (#31063) --- .../xpack/ml/job/persistence/ScheduledEventsQueryBuilder.java | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/persistence/ScheduledEventsQueryBuilder.java b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/persistence/ScheduledEventsQueryBuilder.java index b065ec9383482..618e680b0a658 100644 --- a/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/persistence/ScheduledEventsQueryBuilder.java +++ b/x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/job/persistence/ScheduledEventsQueryBuilder.java @@ -93,6 +93,7 @@ public SearchSourceBuilder build() { SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); searchSourceBuilder.sort(ScheduledEvent.START_TIME.getPreferredName()); + searchSourceBuilder.sort(ScheduledEvent.DESCRIPTION.getPreferredName()); if (from != null) { searchSourceBuilder.from(from); } From af88fab0b3a57794a50a9bd9bc78d6f296dc67f6 Mon Sep 17 00:00:00 2001 From: lcawl Date: Thu, 31 May 2018 11:44:30 -0700 Subject: [PATCH 15/21] [DOCS] Moves machine learning overview to stack-docs --- x-pack/docs/en/ml/analyzing.asciidoc | 29 -------- x-pack/docs/en/ml/architecture.asciidoc | 10 --- x-pack/docs/en/ml/buckets.asciidoc | 26 ------- x-pack/docs/en/ml/calendars.asciidoc | 40 ----------- x-pack/docs/en/ml/datafeeds.asciidoc | 40 ----------- x-pack/docs/en/ml/forecasting.asciidoc | 66 ------------------ .../docs/en/ml/images/ml-gs-job-analysis.jpg | Bin 93755 -> 0 bytes .../docs/en/ml/images/ml-gs-job-forecast.jpg | Bin 268782 -> 0 bytes x-pack/docs/en/ml/index.asciidoc | 36 ---------- x-pack/docs/en/ml/jobs.asciidoc | 33 --------- x-pack/docs/en/ml/overview.asciidoc | 21 ------ 11 files changed, 301 deletions(-) delete mode 100644 x-pack/docs/en/ml/analyzing.asciidoc delete mode 100644 x-pack/docs/en/ml/architecture.asciidoc delete mode 100644 x-pack/docs/en/ml/buckets.asciidoc delete mode 100644 x-pack/docs/en/ml/calendars.asciidoc delete mode 100644 x-pack/docs/en/ml/datafeeds.asciidoc delete mode 100644 x-pack/docs/en/ml/forecasting.asciidoc delete mode 100644 x-pack/docs/en/ml/images/ml-gs-job-analysis.jpg delete mode 100644 x-pack/docs/en/ml/images/ml-gs-job-forecast.jpg delete mode 100644 x-pack/docs/en/ml/index.asciidoc delete mode 100644 x-pack/docs/en/ml/jobs.asciidoc delete mode 100644 x-pack/docs/en/ml/overview.asciidoc diff --git a/x-pack/docs/en/ml/analyzing.asciidoc b/x-pack/docs/en/ml/analyzing.asciidoc deleted file mode 100644 index d8b6640f2c8f7..0000000000000 --- a/x-pack/docs/en/ml/analyzing.asciidoc +++ /dev/null @@ -1,29 +0,0 @@ -[float] -[[ml-analyzing]] -=== Analyzing the Past and Present - -The {xpackml} features automate the analysis of time-series data by creating -accurate baselines of normal behavior in the data and identifying anomalous -patterns in that data. You can submit your data for analysis in batches or -continuously in real-time {dfeeds}. - -Using proprietary {ml} algorithms, the following circumstances are detected, -scored, and linked with statistically significant influencers in the data: - -* Anomalies related to temporal deviations in values, counts, or frequencies -* Statistical rarity -* Unusual behaviors for a member of a population - -Automated periodicity detection and quick adaptation to changing data ensure -that you don’t need to specify algorithms, models, or other data science-related -configurations in order to get the benefits of {ml}. - -You can view the {ml} results in {kib} where, for example, charts illustrate the -actual data values, the bounds for the expected values, and the anomalies that -occur outside these bounds. - -[role="screenshot"] -image::images/ml-gs-job-analysis.jpg["Example screenshot from the Machine Learning Single Metric Viewer in Kibana"] - -For a more detailed walk-through of {xpackml} features, see -<>. diff --git a/x-pack/docs/en/ml/architecture.asciidoc b/x-pack/docs/en/ml/architecture.asciidoc deleted file mode 100644 index 6fc3e36964ff7..0000000000000 --- a/x-pack/docs/en/ml/architecture.asciidoc +++ /dev/null @@ -1,10 +0,0 @@ -[float] -[[ml-nodes]] -=== Machine learning nodes - -A {ml} node is a node that has `xpack.ml.enabled` and `node.ml` set to `true`, -which is the default behavior. If you set `node.ml` to `false`, the node can -service API requests but it cannot run jobs. If you want to use {xpackml} -features, there must be at least one {ml} node in your cluster. For more -information about this setting, see -{ref}/ml-settings.html[{ml} settings in {es}]. diff --git a/x-pack/docs/en/ml/buckets.asciidoc b/x-pack/docs/en/ml/buckets.asciidoc deleted file mode 100644 index 89d7ea8cdeaff..0000000000000 --- a/x-pack/docs/en/ml/buckets.asciidoc +++ /dev/null @@ -1,26 +0,0 @@ -[[ml-buckets]] -=== Buckets -++++ -Buckets -++++ - -The {xpackml} features use the concept of a _bucket_ to divide the time series -into batches for processing. - -The _bucket span_ is part of the configuration information for a job. It defines -the time interval that is used to summarize and model the data. This is -typically between 5 minutes to 1 hour and it depends on your data characteristics. -When you set the bucket span, take into account the granularity at which you -want to analyze, the frequency of the input data, the typical duration of the -anomalies, and the frequency at which alerting is required. - -When you view your {ml} results, each bucket has an anomaly score. This score is -a statistically aggregated and normalized view of the combined anomalousness of -all the record results in the bucket. If you have more than one job, you can -also obtain overall bucket results, which combine and correlate anomalies from -multiple jobs into an overall score. When you view the results for jobs groups -in {kib}, it provides the overall bucket scores. - -For more information, see -{ref}/ml-results-resource.html[Results Resources] and -{ref}/ml-get-overall-buckets.html[Get Overall Buckets API]. diff --git a/x-pack/docs/en/ml/calendars.asciidoc b/x-pack/docs/en/ml/calendars.asciidoc deleted file mode 100644 index 117ed5cb42cd4..0000000000000 --- a/x-pack/docs/en/ml/calendars.asciidoc +++ /dev/null @@ -1,40 +0,0 @@ -[[ml-calendars]] -=== Calendars and Scheduled Events - -Sometimes there are periods when you expect unusual activity to take place, -such as bank holidays, "Black Friday", or planned system outages. If you -identify these events in advance, no anomalies are generated during that period. -The {ml} model is not ill-affected and you do not receive spurious results. - -You can create calendars and scheduled events in the **Settings** pane on the -**Machine Learning** page in {kib} or by using {ref}/ml-apis.html[{ml} APIs]. - -A scheduled event must have a start time, end time, and description. In general, -scheduled events are short in duration (typically lasting from a few hours to a -day) and occur infrequently. If you have regularly occurring events, such as -weekly maintenance periods, you do not need to create scheduled events for these -circumstances; they are already handled by the {ml} analytics. - -You can identify zero or more scheduled events in a calendar. Jobs can then -subscribe to calendars and the {ml} analytics handle all subsequent scheduled -events appropriately. - -If you want to add multiple scheduled events at once, you can import an -iCalendar (`.ics`) file in {kib} or a JSON file in the -{ref}/ml-post-calendar-event.html[add events to calendar API]. - -[NOTE] --- - -* You must identify scheduled events before your job analyzes the data for that -time period. Machine learning results are not updated retroactively. -* If your iCalendar file contains recurring events, only the first occurrence is -imported. -* Bucket results are generated during scheduled events but they have an -anomaly score of zero. For more information about bucket results, see -{ref}/ml-results-resource.html[Results Resources]. -* If you use long or frequent scheduled events, it might take longer for the -{ml} analytics to learn to model your data and some anomalous behavior might be -missed. - --- diff --git a/x-pack/docs/en/ml/datafeeds.asciidoc b/x-pack/docs/en/ml/datafeeds.asciidoc deleted file mode 100644 index 885cb2a83f6f9..0000000000000 --- a/x-pack/docs/en/ml/datafeeds.asciidoc +++ /dev/null @@ -1,40 +0,0 @@ -[[ml-dfeeds]] -=== {dfeeds-cap} - -Machine learning jobs can analyze data that is stored in {es} or data that is -sent from some other source via an API. _{dfeeds-cap}_ retrieve data from {es} -for analysis, which is the simpler and more common scenario. - -If you create jobs in {kib}, you must use {dfeeds}. When you create a job, you -select an index pattern and {kib} configures the {dfeed} for you under the -covers. If you use {ml} APIs instead, you can create a {dfeed} by using the -{ref}/ml-put-datafeed.html[create {dfeeds} API] after you create a job. You can -associate only one {dfeed} with each job. - -For a description of all the {dfeed} properties, see -{ref}/ml-datafeed-resource.html[Datafeed Resources]. - -To start retrieving data from {es}, you must start the {dfeed}. When you start -it, you can optionally specify start and end times. If you do not specify an -end time, the {dfeed} runs continuously. You can start and stop {dfeeds} in -{kib} or use the {ref}/ml-start-datafeed.html[start {dfeeds}] and -{ref}/ml-stop-datafeed.html[stop {dfeeds}] APIs. A {dfeed} can be started and -stopped multiple times throughout its lifecycle. - -[IMPORTANT] --- -When {security} is enabled, a {dfeed} stores the roles of the user who created -or updated the {dfeed} at that time. This means that if those roles are updated, -the {dfeed} subsequently runs with the new permissions that are associated with -the roles. However, if the user’s roles are adjusted after creating or updating -the {dfeed}, the {dfeed} continues to run with the permissions that were -associated with the original roles. - -One way to update the roles that are stored within the {dfeed} without changing -any other settings is to submit an empty JSON document ({}) to the -{ref}/ml-update-datafeed.html[update {dfeed} API]. --- - -If the data that you want to analyze is not stored in {es}, you cannot use -{dfeeds}. You can however send batches of data directly to the job by using the -{ref}/ml-post-data.html[post data to jobs API]. diff --git a/x-pack/docs/en/ml/forecasting.asciidoc b/x-pack/docs/en/ml/forecasting.asciidoc deleted file mode 100644 index cd01aa0fb77ca..0000000000000 --- a/x-pack/docs/en/ml/forecasting.asciidoc +++ /dev/null @@ -1,66 +0,0 @@ -[float] -[[ml-forecasting]] -=== Forecasting the Future - -After the {xpackml} features create baselines of normal behavior for your data, -you can use that information to extrapolate future behavior. - -You can use a forecast to estimate a time series value at a specific future date. -For example, you might want to determine how many users you can expect to visit -your website next Sunday at 0900. - -You can also use it to estimate the probability of a time series value occurring -at a future date. For example, you might want to determine how likely it is that -your disk utilization will reach 100% before the end of next week. - -Each forecast has a unique ID, which you can use to distinguish between forecasts -that you created at different times. You can create a forecast by using the -{ref}/ml-forecast.html[Forecast Jobs API] or by using {kib}. For example: - - -[role="screenshot"] -image::images/ml-gs-job-forecast.jpg["Example screenshot from the Machine Learning Single Metric Viewer in Kibana"] - -//For a more detailed walk-through of {xpackml} features, see <>. - -The yellow line in the chart represents the predicted data values. The -shaded yellow area represents the bounds for the predicted values, which also -gives an indication of the confidence of the predictions. - -When you create a forecast, you specify its _duration_, which indicates how far -the forecast extends beyond the last record that was processed. By default, the -duration is 1 day. Typically the farther into the future that you forecast, the -lower the confidence levels become (that is to say, the bounds increase). -Eventually if the confidence levels are too low, the forecast stops. - -You can also optionally specify when the forecast expires. By default, it -expires in 14 days and is deleted automatically thereafter. You can specify a -different expiration period by using the `expires_in` parameter in the -{ref}/ml-forecast.html[Forecast Jobs API]. - -//Add examples of forecast_request_stats and forecast documents? - -There are some limitations that affect your ability to create a forecast: - -* You can generate only three forecasts concurrently. There is no limit to the -number of forecasts that you retain. Existing forecasts are not overwritten when -you create new forecasts. Rather, they are automatically deleted when they expire. -* If you use an `over_field_name` property in your job (that is to say, it's a -_population job_), you cannot create a forecast. -* If you use any of the following analytical functions in your job, you -cannot create a forecast: -** `lat_long` -** `rare` and `freq_rare` -** `time_of_day` and `time_of_week` -+ --- -For more information about any of these functions, see <>. --- -* Forecasts run concurrently with real-time {ml} analysis. That is to say, {ml} -analysis does not stop while forecasts are generated. Forecasts can have an -impact on {ml} jobs, however, especially in terms of memory usage. For this -reason, forecasts run only if the model memory status is acceptable. -* The job must be open when you create a forecast. Otherwise, an error occurs. -* If there is insufficient data to generate any meaningful predictions, an -error occurs. In general, forecasts that are created early in the learning phase -of the data analysis are less accurate. diff --git a/x-pack/docs/en/ml/images/ml-gs-job-analysis.jpg b/x-pack/docs/en/ml/images/ml-gs-job-analysis.jpg deleted file mode 100644 index 7f80ff9726a1eaa49c3f1aee04a374c783a1d466..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 93755 zcmeFZbzGIr);E4_y1S%11qA6u8;dUKZo$3DP43^; z``q5Qo^#&kd4Hd`{y3v^v1YDy&CHrvYt4585ML0B0MT7V6-5990sv*?KLD`=$SL^P zSp$HY8o&(z02TlWw*%0S6p{s?Mn(WYd5!XC4l4O;)IVty?C&oTyMUOct+R)-yREYe z<4wLBfY@ynHMH*~Aj1!u?FUITMi(;`4^*LT1!KSb3cnqQSjIb4k(W2q)Yec`xu@`> zQFyE7E-sEJL;wJG@^I5uy3J@{XvB!Q1mFTR06wyXjOG^ZF1Iu_?|m=x&!0ca|M@tc z_|bM?l=pjCKePXP1hJ)+y9H8sO(gpxOLq$}lCDO^&lWCj9sqzEjLc{8_Hg-5=Obw{ zH)I2mbp3bQ<`4SwclyyE^x_X59c_6e&mppV@yyNLYybccnGG;{S=b=U!DB?yH=Hc( zoRIYQdSxtZ%`K7ib0mEo40irbHzR4zM}I5F=5MsQ`Jz5k`S#{_zw6TveiskTpE3gX040DC&;=X;55NsD2NVH2zzMMOu<}9bBLK)d zyZE}<+1Pq8-a=ZC6{Cui1>bc>!5adi0Px)&zw-dV0mTnH15teZEAMFu07y3=5QwI~ z^6m}+K;=UKz^VBwkJA(Yh&BM=eY1t9o7a!xez+9?9l!wy0W#nkKo770oB%H%2#5fZ zfE=Iz+yyiM9l#KH09XLF02tYFZ@?dT0)zq4z;hrONCUEgJfIjT2daQNpc&`@dVx>C z5HJqR0E@sHumeDWW8fSF0%3yiL8PE-AO;W{hzBGH5(CMA6hQYt+8{&FLy!%~3FHa# z2R#KvgAze$pd3&Ms1now>HvKJ4TGjYOQ0>#KIjYu6$KB4422Gb9fco74CNMzDvAz@ zDT)n>D~cb=Gn6=#mngX?Z%}GcI#52LjH4`~?4TT>0;ssC6sSz7yr^QR@~9f9MyS@P zZm5B%QK%`Xxu_MWji`O7qo|9hUr|rdFwjWR7}0pqB+-=7bkQu(T+ss2V$jmiiqUG( zy3t0_me8PRSLpcYwCFtO66h-E2Iw~E-soZIDd>ghHRwI)}d?S1h{5bp){4V@?d^iCq0Uv=1fh9o@K{`P#!3e<~AvPf!;Vr@k zgnoo6gzpFk3BM9y6R{J?6PXhQ5~UM05KR&t5t9-N5Ni;FiDQUMi9Zl;l3U*#r>LTspg5zXqr63FMHxw1K{-NsLPbL*M`cA7MFpW6r#idFcunD& z!?lEKb=T&o(WtqpwWz(Rv#5KhztWJ=NYYr)MA1~yOw*#!a?@(lKBmp1{Y-mAM^C3j z=R)_2u8Zy~Jq5iSy*>R4`d0ca22utY20Mlq3~dbCjO2{B7#$g3GIldUnP{1mnLL?t zm>TX+ z?BVQn?3)}^94Z`s9AzA{ocNrwoUWX?oMT)VTw+`fT$x-$+$h|_+_v25+=DzQJR&@H zJefSh*U_(wUw68mdwr4@kM|a@7jGHw5+4QMJ-!gWI=(%AR(>P?1pYq$s~f^M9B<^` zm=PcmxGNAM&?vAk$Sr6gm@YVW6aS{-&7hn0H(^3NLRLaqLSKYQh1G<^g*$~WMMOp1 zL@GqKL|H{2ie`vTijj$Fip7Y%7e^PrEgmG^EPg5>BH}O<`V%LZw6n zdRO#rz};?DJk|TEX{yWjxbL~$Yg9u~yQ`L@HmlC2?xbF)0cfabBx%fPa%j40HfdpK zX={X6=J`ilnq1_1`2 z45YR@OGf_N$$| zU78)tUfDj|{=`AUp~wN@sP6~?V}T!n8=Od-9GtqH>79L?hh2DF!dwC>f zh3+7CQ}=ogG9>W%?8)gF>bc}4u>?H}S_@VRE`EaZ#NkPQ$c>Q1ki)0?PaB`nJqv!e5~>th z7Df=}7B(3!8J-=17GW1L5P385RpeEaWz@&$8__Az7cmwwA7ce#U&bQhtm6jaMdGub zV?1|yK9L}sP@G7d=$E*Xq?T0sg7HPvi^F8I<=^3I_Z5g0 zloV1IMi*WdITbAyYZrHyh?bO;(w4@Tp_F-+ZM`vhGgN-3yuO0BA_qbNiGB;b^?bWs z`LJ@LO0}x$6rwn_t^eyG#4m4x5gZPP5LLE`zSIZmsTt9@U=ry^6hEeYg7B-b=r4{vh$8 z;iK5cx=$jXYCj8quIU%-s2vm?tRE5|Y8;jtZXJ;w=@`8;+B>E)_Gw&we0V~4 z;>)DTGPT3S@hYcIik6gdD{8h1+E3iqR3*)(w(Kx%lDUORxDO_ zR^3-G)}F27ucvGZzZVhc4Z?EmR?3{lM+a=!3*yG%*{wDYBGt>aO26KZU z_G1pN9TXi39d;gR9?c(vkIzq{;Md^Ar(&mlXZmLw=iV2X7cVclE*q~@uVxWo1j5DK z&HM)zKt(=LtdXmd{UQLsHv|AuB!<8-{sS-n-~j!B@safRb;|enJ^V)hfvJDI5dnY- zB=H>@$+rW*TV!Mp1^_}i0Qe4(bmRb(n>T+(WX|{CZhcem2LZx!0|0b50&zeG0GN#c zaOs9XoM$2sm&i2$>J$L9yZ(XGzjMou00H8z4^#31RIBflIj{Y8#@Ol7q^hGh^Uyj zg!~-^MI~jGyZ3c;_4JXD%)-*j+Q!z--rd8~%iG7-@9DG9u<(e;sKlff$tkHXU!~>d zFs;};p52Y*!aZcm#OKc<(1X7^^MJ~ZP@<7;nDF4 z{PgU*Tp$4T53znq_M2S9NV!nZ&`{AZzsm(e@kT~eVl;Fn0SuB`TA1dpq|Aa(u*hyF zqo%(N5K0L2)+lxp8T6BB69i=<5LE)6fk{Mpy?On0p8v;_$? z=}$XeYgo(|LtZkC$LrBY;=8;z~1suW@t^!MP)5@#M zEtD$+l`E#~E1jBf#r5eg_SDT3Bd1q31D`8C#=c`{lvIa}!QyVJ^t`^Wek@%Pby{Qy zOUYZpH|}fvnilY;aXvChO7o6g+lUe8f!FS^H@;%WV@Y9ncCs>!-uBi2c8I^x7=9{8kgt3Oe4wZIYZ}g zj&~z@<*i`Vn`p_KRucj=PUat0uB|sRgtn1$z_J?3d@MBUM5fwCU~Dhr)nI&i`F34ebxDf8M%em3u`8b70ct^cTGHfA5JVGhwOszVr}o{p=vh{D z=@eLlTaB#{FV4MzO+}TQCB_DG3`g96D{q_=LI^K_ks3j*=KF8z4Dpil#&qJ}wNn_| z6QzqtNT^W;FvUMei@jNaiT2JjkNe-uhx2Px#x~36;+w9v+TqOLzsFgYqCD@AquR(= ze3Yn<$r}IKUc4}D{^s?)%G@JsMo^YS8jMbKSt+98g8a?4M6{iRUQLd@;8q>U+#su; zuk9;$=A?tgGAqrDq+W-Q{#r2lgFacjX6O8E?Jo~ha|a6_?cB2w8SQhGa=gL%2}3*o z#)pjpVIsH6V+Hc1)CCHsLtg$qC6k&+Pg(4b=+#<#xSseU@s+jM9DExV7WHCpNMVwF zRq&Q(IeD7f2?XM=D^MpoP=`T}(KoOZA09YENXSy=H$ZfGS9Sx!cp`D`rny(@($ zT@k6ts)Hpv4`}QHXZIs3_E=&q6PWj}4BGL?Zeo1cjXGc;GP9SZkaAw6X?n~nvZFXw z{i$pdEKHVYi58LKEKG@Gc`rHUa9cy`jz!SUI@jHW$@k~jh6Wh-pZlVD7eH9yMJoYH zOINA+naniCKF)j!)v2k`Oz)~S&ByG zG2NSmJRJhBP@TMKil_0ndIu9pT9S;FymM|A0bXmUd#>WTHjNul&iq;8qns5`*sf87 zjhY;vYYUNtyDpd8^iX>hF+`N-)Q$_8-VTsi`PvghBE)2%LXQAm^6(H4C_{LLn%!4g zIPSwkA@JPCl9_~E-h!vk71<76C^*Jb%NgwAOwrU4HX9t~E+qH$Unz}}=|3@opD!yW zi-z+zTNK$v7y1<1?wV7?bESAl|E%C3ASd)H<>n z^6^AFjy-cd(jp7ntF$^cS=9=7(z_^-btpW0S0!7aDc^pO1zi^{Q5`@nVSnb4OriWm zLJW<_4NDqJc)wYeT$rD98vd@6I&(dtG!%Nd_SM@+@}q@msfABI3B|@b8j*{V{fTT? z(7w7qZ~PhhRM2K}(We3gP|>zZyD&L-W#gqE)-8dT8mu5UDOh3Z{uLK0&W_~UyIE0uVIMPr@X+}JZz>ei@eIxU}=Ds}T? zn)!5Tj0ROXPpXZ1Jl^!gwX=*Ki2wXdaM$BwV!puUt%|ECwb=r42YQxrfA%r|TbNPC zTH`B}ft({>zq0x4zE@tYU1(Ie&%|cXhMOfYHtA68BMfOaT*@ZJef_j+Xs+|oRJQ1@ za%ASzsn^#*`HbU=^(a2RJ3h5#(C~BhQA6VGa)$ula`px*mjsM+-fmY``!_Ml2`)u0 zV(%SYVJR|Flv0sT)Im2r`Xu99 zi8q=`zWA3#GsLU48ocbc=|%Lv01s90C(9ozkg*eR9?bD~=%-`})WKq}Uf134%j+w= zTZR>(!u)Byx(n}iNKi0=v_tCn6`{f#LNcMWybhU$Vxw)nsy?bY8&}(i$_$b_8HLJ> zmL$?U)5W<6U~*u|>eA0(e@?Qijnw>IE9E@v+jElyZlh*ur|vj~hpO+(x%lhx!02)V zN@B(Sq|k%=L(RISKBH!>H4S4mV$8Lcl{M$AG|Z1?W+}aVvBhRJP@|5bIP2Z=x`Y=( zWtf^^vJsvT!krH`a=#ujj)$&FPwW@azd7Zlt#|21Nv^^08ZXzkSXkX1YP3Ojf^Zs<`r(p&T*FVTBiE>6grY^(X9mdhT~`o5 z*cA^9);J8QX<{4V%a0wW(OB?xqC|_Z7DUHWUOKk4X?d)yYqAU2BpnrLW<_H1ZM+ET z#9Wr<*M#v^F2&l@sP+eLPb>uvJ8bkuI^%Q>znw3rTakQ%_IMl;{s5?lTAs}p6`OXr z20%<$4|ogeYieV9(}6hY&u&WByVqjsTd2D zXFf=mjcw*gVseYiQf#$ykCnfU@0^Y;k1k^n=i62Ld|y#fY+u2(d9i3Ds1LA2RzsOYT5T%2-Wwe~?fNmxf$`U;8whqEWNe%r%5t z`w!Nj(bUXgCC1;>&ew0run-;GbUwuY+)KmqS}7e~J)v)Rn)peh+bZA$P`-4ql zpSJFj(ya%S$sE;TJQ~b~g^_n}pO82|?7iW~sj0zU<;f5--G3avEQ^cp$2#m8-8WV~ zG`*KbQ@_ycWig`Ald>R`QLVn0gw%7A99=i^%wXE82rZw5D0_kvd56Ye0+#;{Z zPC&yJ(5AzD`B|B95AC3x3YC240o8DPxW8zDEryxYR_)sv-*m5U` z_%DMVT zps$Cf_I!I{)5$;#smNBUA74A*eSIz;kk3rc=ENj+N~giN@ieSsxy@S26eg(%jeA!F zcT>f^G}apfuQjTg$}9{%H*Wt}rF_e3@#d3YRr>Y`-&W1H%@x9AFCe9Rb$bqpHX4)z z1!^6=(=vlj5r=6!8^-)`wP()J{u;00g`G!^)h*VO>QQI7A|feUzRr&3#*y9u>uK89 zKq$KRLm~|ojy_q8zVg=R;3JGW%Bro%VqCp*yvAotbw+(6zDaIXsKKEfay|7BaGcbK_Eg_8yGe=bC+oZt;}uSN1~zxDyR>6< z3apeo0zNEf7heqp5q@2aJ9}?tKY?rRTxx1+Ff9e0GBibbl(q`hB-eZN`evy1-Qb%l z;GmteA+X`h*;S47$Ebt!wx~ej>d~5h-SvcBe`!y!o!i#6hn7vs^eps*p9`E=#Obe+ z2ZK5fpy3y+ZazL!+vbep`U)xMU%|&zN0?076zQ_PhH?*aLfT2NbLY?li{1^JiEhg> zI6C`lEM;g(@lt)d&@kMhZd4O=13iqTzQf^PK zvDFv+HV%7%%=Tvppj#upjg+yaMa5Ii=6)t~2-b_2i_zX#(F5;?+*D4i#Xmr%oTHIW zU)VWvB4ygMd_CO;Pph%Kr#~iXe)`^*o}T1xZ=z~J&aDo#6>(a9RfZn^XEzdueVXKN z`+QuOA&|u^K>$nO3vL9EGpK+7I%1J4O4_0fYgiArYmB%BUFwlj=lgv_b2^oQBB>&W zCS!-w)(y7DP(O!$%pPj432bL#`&x2mnK5;li!ic=s~MnEphSL3TFqgM|My@5GB%#st=ElXJIwjHh`c zIMv{S`0Pu=$T@GnjNRqdSQx`I^%jVazL9EzQ!8~#+P6Q^hGFW!V5~Zw5Z9-#d#Bjek09xBzFj2P?)Y&6-713>$?RP# z&qU>%Q~gKGNhvH+`V|P^_sW!hZ%*P!SKIwQPmN$1E?BPN#&+!)pS*# zimz#VqACT3{vEZp5tiH{G0%P93%B!sJt^Nb5*`d|CSFc{J1ShxJgGD;Gj4PIY7U%d z8{5!q>PPa;7!Ef}E;|IscBSnO zq-ii7GEGdx$UnnENc@H9qBDli;BgGRO3E~6%0bpLUVcAt$|>pe@vgDg+~SHChU+9s zYda(@kQxDe==C>8?p^v}UM02wev}uS3r}SaS!~jxKgI?0KPtcxjXtkN^gJCCCUE_Z|pNZOcoNtXa;hB z)7+kt&9m{WxQPd(jT7qvhUMMf-g>Dwh!RQb+qS+(BAj z4E!bnxGjP-^>@OL@tMd#n*&dpvuACiuzN*@EBj{X31OCnz#e}Vc4=$0c zcMIiMBg(*L0(GbZD;fH=7m6_2EL!M=tYt&mg63F-`MYWnC|fr~s)&i0%_E*ox4{cX zBI8g(G2Kn;s;)9)o3rP`p&-%+D_&3`eJ~Bu2e)I%!qa4t8Q1=vaqul1IZ9GmWjoaL z2^A*2dJZjKBVInsDy&xn0#wny_h8|mnZRCdSA#2hSays*Qqc)bB$h<_^X*T-c6iE< z8Y#R#Q3nT@q6Bxby2m#=6dGLPC^H*J0Pk1g%rUAp&g=q5DW8?Y& z9R`Wss|muaeOGR@LoqKjy3ry6ZLg%Eh$OkSR+TtNHE-d3GqasGPQl4vXXF-);YrOx z&1{)``SeVA<43&(lIx+Fc~rA-0Hr%v0+e{KndQD_(!v$a#jsW{*L_cBq!VVnIJ;?c zMdsWQmkoW2oJ4V_YRWXR76fw zD1=w+X$S!I3Rf|fH4AH)T!%#EZ7_hTtv>w;ev*$=sqhog^}Y3la}i~0gT)u!i4CvF z{fC;XD%>c=1~na$;pG+ZY^{1&QMkvY^}?OELx+SljjA|zC&Sik^za50-;XKPaSg1m z9%4!uI9a9zAOMX6p|Yseq-fJt@3vFA{R=|)^=&#S;#|SE@0mMMuwhY_up#$lTS)T7s-5CY=IloA1w2DD6hnwv@p@T~rp`QC|hpNWAw{N$kLo%KXQ=8wWnm5*?$Su*QkGG zQR&$?Cuv2{S1-R~cFSLC%(LI3Lqg`=^6j>1>Sws_%%!_n>} z9$O9f-OisA+iQdD3}>AD<~fm`bnx$<)j*bH-C-e8mOx6>n?y_ikU(BliL zTx?v<1C5)`Zo$V8TqNMxSy>V(D&6!37jLD7hYM#qt4hRX*5raKePRUfFlQDDkUihn z1>q85%_L&7AppqEy4RO8)qj@$@4XQL$yitp>QR&JqP*ftHE2k`RXG}CmNk+llL)4M4pCbEkz^X{0+>%UE$*LfE< zG39vY11fgt;B=Y=tLl1LC#6H;Yjixf3mVwdW%P|O{$}@z9euSN)x0mhB$>=)&mD|n za)qPjdAF@&RT*!8CfhsBXJKV4o_<$(==|F-s2~6w(Z!Cf#Q-FL1Q?N53mn#GoM|sK zVFV=wo0M6s>B{w^7mtKWSRXswlB!hAZ<+3Md9HdLJ@H<}xFc=F;x$)Og6L%kxhcHh z0(GfheY6t+Os8!`TBV$V6YW^91`~-`?z}j)R>A94p$hTJX{VFFi#!o2I*mjCX7Q)= zYd;#$cZoI4e+Aq^V)+q-D^(%Y;2@H{0h?N5R6MG99#Fp?mq|9w`%U zrnhSqwap_;K9TY5b;(MS6u%)?7c)g}KN}^3!N@0r269S?g$w*X)&4z0c-4;~Qbybd zVmx%g6Hqb@*Vnr0OxJ8f8KJ3r908%8=dDj(QAhy1H3zFNN|o3fb{OL4StdND*i(YO zeh}gnp`kM{p5`4}fF{nHUdGYb=6Wlf8gV$@MDI>Wc_@)Rxp8IoJl;1b#0+i4(ol*t zr{wvrrX#q+BE&`JfjUT-<2U^=lir-a0n>=`j3+RFS6HVUbj^z=cCe=L_!MDZMoYEd zOQ}*NIJCQ)89Rg*JVkzZm6>lZF&UgQToX?$eK|K*mnu?T_^jGaHDHVBi>U>x3ry0$t0t8TAK?lBc8b;~~QbXGjz$=EoPy4^%fYZ9Jvw*k)=*|-5Q_pqZX3^rEwAh+e z_q$)~WNj!19nkjrUys!wn{=EM}14H1UWw9JKfwV}YDcw`bgH|x|+@}n#$Uq5Ur zW~q&%NUp3Bc{R%6{k};_PA+V`{L&i%ups9Ot!#{-pOac%(qd|dSQNHDX--Z;ZG|Ja zcU@}H%2&z*!U;En;V#q7eGBo_pxx0+^`aLV`X(%%6E_adt$b|8^di6Mli-V&-wv=l zuAvd|l)}#@^+jY*B@~M&UP)bXyftv9qp*zs9OgpBL-a;j%p}7yu7#_{IyHO8oELKG z=p_rylfgp({~j6o+B}ot^yz4JE`+m~jPrU@Elzp{use)}nx7j@8}xWn0=tG<`CN?Z z*z)bGc>ScyW^v6yWw!IzhA$NCa*$IpT-gZ$R8ve#K9!QN&IdDwk$deAurRGUsQ?z& z*i&_y;%2gX7&`bv+)@piNpl)vb{}4UC~17HES-cGJ=JoE_e{(g4v6wmKas#seeaB%oIA0}!RQ?abiijjXRZ>#9EdHWrn|J`RG@%pa-UU=O0 zhJE7H_FH?SS--pwz8*{|(?XHukE}c8yi)O5SwcPwYUo0qKX?y!UQ+62Agn0zo4{V- zdCc?aQ*_be>`IgVN2&J?5~-Y&0=kI+4k|h}XXl-w)7WzUOXRILmMx7xX1YHi&OZ>( zpEF&nxACrV`<1|?KL}cSOh=>A0Hcq!pxW;lqfk8VHLMuHdR3dpz$ZGBnUl`u%lLIu zMi34m-^=!1W*|1UPkZcBwbHpi9V;UiIP4UrLrJjR{buF`2_<%%$U&N&ne&eG!EHZ# zr29Z(_G6?f|6;Vrru^N8E3Z&hg&vTMOUWG6^w)(8x7=5)N%+zfkTSjWjMHG>zlK@r zjQ6n>qZH(yXNX_1lTL2%f0+K$1xPJO+*tJPD5yXX`U2;lBIBxet~i8kSULUXD=C|jj*k-qT^0n9ZafRTn`)XiN&(tf~#eb5CeY&*WkuU~V%Mq)Cd$RMS;uz05o6io;e6Nv0w&_>UfX7|z6JA`RfcQ5d-Uc} zCdHlEB5s$i;;;6ya3!Jm)8&PeV~s2B_`fI8lGHcVxyo+R2ZaZsG>j|{+dz+=e!0bz zCWc=fXr!z-vfboD6^Bjtc>LXBJm&7Gj%}^Ikd2@r2nFQ$*_)IC^Fz{yUh(x54Z^M4 zXJo`OBZ(wZQxYNdSNwj+DFJIe0Rc!EUtN7b06n_rh9@_ViLP|?hA(KAWC<5cw*4sL z?TY5+Z3a@Xv_<_hyD2mYuvgX=k-Z5N>90`5$?K(yQ_QjX^_C~z+O<9-66a-w!n^(%5By1ZF|R#ahKfC zgjf!>KfMVhzE|{G1;x^KA zgU-WrJ6_cjB={<^V+$*ArW>!WU!aYmqd_Bn?jyz`99aS9@08)J583JVp`|qg!TQ?r)`x*v(uFz7tY5pJ(WwdmG!Za9~5{yQBJB|7-o0)?R-c+apcQ+mXNJ z)fhTa4z?rHugewA@>C$X%Z$e8g?gQgH0H41-LI}I8`znSNo%cJnv=OYGtJq^nigjT zKgCUXsM5ZuH~5RL{;IjU)QRd_N!(hA?~I6NeT=*GpK4M1>AvaGzY}-h&$(cy+&gCI zCgYM9OyDA+x9Zx5=RkIsmK zP$dPa$*DK}$Z}H(_(|cS_h4%CktL=dcw08Yzv&%M*c$MJeHs2hV@YI@B5LWmN1%v> z=F-XrCx#*bUFgKSTpwqZD(Lw7J5nXK-Q;{#_DN4~#c8r;H}DLzC5E=rwSGsMUDAQ} zN_PUk(-Eh>ikoNp`gZy7z+)!is#G&O%l9(RoR&*HtjJ55vzP?~cVrw>kBy@qr;ZzI zj_mGH8!L%WOiRe;ey)waq2+4H&ThjF?)V&BqSL;NymuVmDb27nm;bqQ`am;lZ++J? zWSG~yMpTtrh5QY-@rRg*7jN-YMGP|14u8@0)L*;f-q?!25;VU3?7;pkxiuABuya;Z z-qSF?`!JS2SCp9QUI`~nU8vZA`;7304E|+CH67vo#FK6TJJE^w!c5*bj@2)}f^8!6 z!uCX2DV+d3yqF6;-6aMy#CjOFO6&Y~9A~);O%K5OAumrwgC-^a`rMNoc_NXFY zhy(6$0YHuC#a{$WRKwS4>Y zXX6SL@d`KRP&0f!M@aQfJg!}p(Y8Ly{yKY2M1CEMSaPZp?tY+CbM}2xj{kuz$eBbd zLyN*Z2;XHA-mQ5nl7av%!{0};?C+j9@2A>QsV#^M_xkSW@-^cwHqFrK-)kCrV_iMT zcJOW4!RMo?S}46`dyM2o*@37Oflv7_it&pR48AD@0el$bYeNPVhpu0LSev~okdG|7 zMD~UGft)Ubc+3mlNjny?@)jD!5r64|8QV1c45Pqo>ku*U;w@UO*PEqf?F@GzzqyOw z-G`P7mzfVo$60pxV5l%Y#lVW9HSe+L6KedP&*{%B!I-|hSq&TI2BQ~TOR;R%Sw;@i zjTJ@~k-I2loFQ0N+z-T{7~_wk3<$7MrMb=itw#?QzYJP}JoT4f>RNIr7vXtKY{QpL zRjV7hRGq>73GW`}`?yl_kQGM4TgFC%&zkv{dAX$t%|^hUyfSnJyn9S4kF-m5l@-xY z$ev?u-4E&%&kq`;Kmcu3K`@EOdt44 z>OgVo%B!mzJ-KVz{?gFv^HlL2+M5*ouRCw4lA_Rf zGDU|}CR7u3XFQoqTdI)_MgWAK;K#~M&BGq2LedNxjaA`y9mM(@TRsopwbF_$RZ6+l zc~HN4c4h}XjuCkI(&j4d`&6!{aPfd@bd^|*rs+f{;RA!&OI=0Y7VKmN^0J|)ddSnO zg$IqbEfW{Kg=T{`Shb<+)lu@aI9LXgZW+uWE)oReEuvvklCJo>&1Y8C3HCSHdOlX) zy)$};h&2&K#@dYch6aoM%IjiYj{uBg^!mEkS2W0a6TSx8SN^7y+TQZ&XSuzpxpvgd zCWY}f>7UkHHxt~fTQtmHSqbK^%gw}RQ*ZO^p+8OsFjtCh3j!Wa~Rs4xD|B&aln-wo2GGb zMcB8Qe`$p>CC#%D+~}~z%zElf!#WEnO3hYEHXdmIs%yWdK=K_Ah(<23mp(b;+u^gm zZMRHV%Y51|G%Bfjz3K))nK1P#0e!vP-lhvK!Gs3sbW2(q9t5Ozy95O9GZI zxg~ibNjUI|yNR#ALL)pWMlH;J+ZQer6IAjKp!qvU(8QP{NA5WN0^EML{QnnukjGwF zdkKGmO>NQeYD?{YQUF6m@WbfU*=zi1p56-jp>2A9&a2xZD85w>i;qql(++K`=_qVR z43-~NfH3=$a*$`@dNo{P)9Yle#OZb(qML92y=GL2iu{jW2mjxCEA&rmt5DfLmR4oc zd(D#hxQ6kGvn)ZM45ek~A!L_{L8}W=99O#wSIPZy3`$xGWB@XP5M$q$UhwqegnHPw zC>cH<$|e0UkB#x_^cEh&3FkMmwFN`w&50j&%|khw>f%(Ug$}-)3RGPCDD;eZA5v;I z={lpD?Ko_Pd7%z3EA>e_Hi7b0LJM*GnJ!#|UfXWrEL>*oPfzc!JxpV3lX2=}q9%3| z742^kJa-s8?0X9fkG8}ok$jrbVNg@C|_(@M%<){?)Qh?WnLQ}L( z*0h~f)ub>km8ZD%lc7Q0nwES(s$f#^<_)$FkRX^wr0_z7EM_2JH_tidbbT2f9gwTA ze2v$}LEI(|%)Wg3TCiPf#W+1ei;9Jdy9abys@LQj$O{>A)AI@p3eh-{*~o3YKPj|>^am=a)xpv0Xb}ds*kWi9JN>|p6$r*kjxI!?c zZ6}|(+xE$9pE`QoWxM)9|1|rp=Yd9-*{RrIjO@{%9CBf;5AlW;<~%O*F;g1%=*?#@5^c}CqVkT9 zkSik6poMozGm}?7Y6u{(UqxY?JN{>i!P)F|N%Znu2;}!Kxq<81`$SK#8a`Z%R7|j@ zcAeiwT~)iP&^WaY(5|>_4jRO6`!@9&cTAU|4sroazq(A5nQuGjbUr_}ML8l@+TB4K zI6HFowvPYvJ zZKC_CmzT}jyVa@~fKEy4#?I2V{59T0yiq7s;Pf3Jd>^>Eb49-1c}2={8}%9)iax^) z%p8^qo}o_d(N|gO=4KD>n3iW^9KETbigQVP9wSNQ$Iw10dHmfoA+@0upR;jV9xMO- z);{(23#T`OG9<2cdGnla($#dGcylvuam~NJ?3&g6DIP3MCRuX(L2mJ7OVE$T4*whj zWvlpLw!6EC*k_N2xFP1E{`=F%=;2(7hugFq2`vxq5 zDOF7c1ryD-DWEFry~_J0nO|1j`^a0VpO$Ie@)Q^NQa@C{T{VRZ@rj!F5@hF)>HsEv zUs@9Yf$NS%A`{sr%qO}q8f zrvj}KY37xn%x|X*-aax1Csordv6hS#&gX?wChbI;^BXW+68& z=qY87`Vl~~=wCIKY*Ti9rIf8tzeIw@Pd7JhQ7t_RN>MKV(5aC>mFs`!$p6htaLlCs z@E-ouKqo9b+R>jOZ+3gqb`;kj%lc05ZiJv~*3B>aFC5IMJnWbR%UeI}^rFrqiW&>@rm@?J0Y=$1gn0=AioJ*#4vI*{Ljt!b?W7 zk%yT^Dvpkpc6*L_&jyMMnroBYKr+p=apP0|0M&@hmjeuPW<8{FwJ9l8AO%0HYX|4&Ehi#hy%*7VROgJ3(N=dl-M z8`)DFS84~HL3?uuV9R9u8>M&q^k=Ea)|DX8Aq4Z^!h!M23y1_f8k)Ma&=W1G$`C=# zYE)&nw{I*dl%R&4;H6ArV92WLd1@+e-iL<;Q7Emen~<=2lR6#S?Ugc&*IZS9M{CF zGV&%KmyVzW(Z`Qnj3Hu-abd-CJAT5UF^!o=mn}6JczPpI&b-eQzxjT2@T85Kdl_nNL_lZ|F6BK0g2W^)pSDwDp1Eh|p?X zl4fhjxHH|O;7{DIQ#ga7e)X{G4L(~U~))!$>t{)zzZL_64H{xTv1v{KxBdp zxxM=Q8N<;#q^B4h&z|j(c*c>m949%XZE^j~{8x1F5;`AQ#FMIrOM2rBzvZP3e=?eL?VHKBj?DYo<5Cnf`dO;cpB|SiC#*dh zeBKeJvJpFeP##w4?Yab^>hSVvi?FJ0it&rAh!WlJ2>>nnER$Te#N6PTqyXfIp9aE%Ig`2d?Yr<mR+L(UHXSc?ZqTrLq&&RLEZE^<$S*Y{bB>gMP+;=n9TVr6R zQ)#EyJ5HH^?2~lliKJOZpa6_~{aya-Cs&sP^vOMH#;?Yfk1@tg{y*m4Gpwn0YZt|W zCY0^Us4LNPP4FJz z_1auDC#nvkk5}I*fqY#(XTdlwhUBj6q2JoZi`*+ezse%0H}^v^m8seWi$D$-r#tM*B5>xc18*ZdyS;pfL^suLb z*0Vn$O^vrJxW`~5V?T=F0jVRlJa-p}CKO3lL z{Gz8*VEY1kKUiY*C;SeFZP%yw(d}Y1S7GzXqIA9@x?J@eos>S=2;I{tcd2EtkZ;F^ zx&bk0S1#SR*4(QP`Ci=FDUY>gEpDPP?2wQ}vP;LvoeKYl$DakHMce%QPF>&&4x5jM zk@JnqvU7P zzu`$9i|x?14Eav`b0WN$VITwGp^i^Xuxtu{Z8>)%cP>G;ZB5 zVFSZM+`=}KxvMJ%MHk{84Zqr)dFa@QdC^;}+w@a`%W1IAZ?-;A3_5F^liI;hSykt` z5@T(MLJDRcHnc55pR0D!1|C*Af)eJwNM3eXz=?ah+Shm=%Jq$nSeFj(Yh;57M=;94 zlMlRE9`KE}ybIp0nsYk3aMGvL@DW&d(bVB=T&R~=W_L;H)M~_-`5nGoB~NB+1=|!# zJ8}=!uvvOGNiKE@sMmj>THY&kq4wHa8(ukbJp8rVQQ*l&^q@!lfG$OYmBDP#);xP` z$r^Lyq!Ed^VIL_?JS{^Yp>|BPt=hEz;{eHdSX)f4v>{dkwQ^0Hroy09O0Nl{)xkF0g!#-d{qSsR^f_z4sZIVmik>wk$wcV|DqSK31bb$a6bDFV^BN(R!hT&9 zRl}F!H!#DmzqSc?*4v3JISce&*s$7n(ZoXo-ilpWR}va5jHQJ@&7N-Gr2HHu&nN!# z{nc_~X`9B}bHaLt4y`$}V$|y%=Eq#+879!xN<-G{imJ-6r+hJq?rx#O1>*3pQIaVh zL&&Rf`_;cG#A>x?4K~Soq`r3Wd4WbpJ?$!Jh~ZPcnJy?LBD9tZm*IDIb+s6p7uA#f zn<6&Prh-Qx{Loi1k&f1zX>R(89p(m69nYdn%*r*h7&l$>VdavjsEaXIuPiA2-3@TUaS{@UbRJj<-@zoPVOmSTORznKCQ64!&|S)DON-q7tzn zq2{7UB1F_zCCW0QiZ?-5gtx6pD{hvuB4fT}wjGV*O{e)7t-Jg1EOg?<9V|v|ipgtR zjDl^qh=a(kPgI{PQkj4FO|xLkOLXWa{%v(Ms)Fy#{#8e5Kkbu-x7KEl%8+#;3(NV~ z4e#v_UQBs*##1cA3gDbcyHU@}%o4Z<2PN0ZOYJ6Fq7$U5bDa58d9zTOb+>!oOQjiO z(-Zb$OC}voa1OMi07y!B?UCcp#W#p+3ANY2Ts6|iq1scr0LOaBgBol0!I~W!^+}T zT}anG5tnd9Szt|mAMHjQJyBv?o8EL6`b`mOSSw?urZ=|Ldn^`f=6%1n@LustyWL~# zn01FIrO)@usqk)>AK;=2O!r;Ps`(Q0EvqWLMQlT;;b6O!qLW8YAJaCNiF9TT#Ojb> zM2@bY=jIP{W1RK%<$HAbtk3gS`5A2Tg#Axg{iR|0de|8t$e4ro(ZzAwmyZYA<`yqK z$dtwI+7)Jq_?x=g4UbQf7?F9qaREM}>xSzo41=~B3l_S=!rh1n3!z%iU^D>?EE7bWPM574O{tz4z{P>yz7l>GA%ngiH$~e%Ah}$A?do1`4hi> zCMF?}eFkef-$7XE!}zQEAIE{7hIRx-BF``hf|>{NyPk(l+hBb>HUw@cZH=j}W}Q%{ zp)d%eFR~){F0Jl)TW&JwTKfvej+66+JwT>wn2Y0aM4PZ>5qFUxM$d&!a*XN!~KB85(teL8ST>v^7I27_h+Mw5@#_K#=in5+Q zd@agyzec>Z&Sc7ng5D+QSP4|-aH}5NPAnF$UAd=SR4<<*j(7R_d2Z9XTqugRIFb*} z_cBI8yhAyHp4A-nS{^%bLA%k}O7CO?2szS=po?BKc|_4R{d-?kVFw=ul)D6@ zs9fz&IH2C>DN!0MEv+`=g3|)c0FWkrL7X14UhgMCEVLpVC~JAH2gBJWpX$Ay(|2w- z7a8UkQtkq!+=NTjIUKjljtM7Nq9lc)GG9-I5U>fyG)9Akt_3VZu7V#&cO)daSKi%u zLtmjTy))f{VpvOIAfhg$W$WUFM-M{psDw+%C4Ub*jSh>!T+l6&4KP~+c2Puun{Zt@ z4?>%^wKW{Gy`waV58cN{!NhLS&DNgd<_M$5p9)p~DcX5Ox)rujwQis3p;@}LxfP~7 zQ`mkV+>ZSfvwJrH6xj;xMia}AL2h5HjGp#_J2!~}$N!}@GA*b4_%DL?|MPJFe{p4u z+s(8ClX@r61pLU(8$5x&@Nda5sEP$}7%QCKlHEb4AYY=6Wcw}wu@~URXSwK84GjN7 z;0^g33ka@VZ9`pEV8Hhdc5b(NM0~&ZW!k1RKrZV?b#3kUPTD&OEY{ih#Q-b)~g zw=kTi*$QAE6iY45{G{$~^RZh%*(S*BThw-A1>Dn;ly)T`AUL@5W z&A*2E1LZuT7`@-7mlJRSePZ_1v}U#nhjE~^P;EH4-8R8G3GcZ{>xTo5@Gl5N{Pcrd!(-^)L#n4I)RAL%wBh%P`3MK zI%#g9P~m=Jn5gl>^NY-hUJ94^qSaxdL)&Mt-ERtC%d639I`9_bm4yAwd;Vqpnb;adUCWh{Zb1-jhFxkXMNg!w&+FDbnP$qc#mRn#uF$SWZITr&#dOKJ(Q{P?|!see_ zAN>eslJzY>rs|VrFsp{x_1lkpY#K>#EJ66nP%<+~gaGwZfXozG>5pLeyp+BV?ghi- zFNqnl&$(W^XVLwwpv7_F^!rT_agB=YCeDwBNa{GtX@Q(#R9KUNc@I?gH-&WG@fsjG z69HR72h{I4p{^s>Q-EV^Cfc%yX%hRPmL_9t>NiF98bH>o(2}+4{qeLh%Iw>b_SF?y zukslk_2#zuoEG+~eLmmKAvK9t{*T0h-{Gh+X4G=+&-5N|R;P|T+)L`M*4pVmi4B@l z5Gh)_w_n)ddb`2fhHOsAw{})re9N~CI~SRv+`eg{7wP?*0<1zl4JQ2&-xOq@z|#}Zym}<^pO>amMw1_0L1OQM z6O3@pQ8e3|7pZW8$3MV}U-$JqY8If#zJ6fSZ$7%S2Ns|}jq?A? zHP3keT1MSTUc>1K^j9)BF=e~a@*0Lfo6c8x=j%aX>X)19)GogC4?MB8h>&UJEbYX! zlg6v3Pq*B+SD}0)&nScvNRz#%O3&r2l^y3L_^Rcoj;dDXFAMJ zh=De(41+kmUHHCIg2@v>wZ}Q5*psMJ`rf{4zZ~lb3&0j3-1~u8rzTLnWjh|9(b@Ps zqjT0SDbIp{N{#;jib2$2{r2^)!9Wae9q(kAce%a%dG}&bhfDN$(B8K1z=ZP5ewk(k z4f}eoQyIsrFTW{5z13`u^ypvbp<4wSUP|$6v-dc%#Z6`Reb3G3Qa${K4aWV+c(4ti z;<(&=r9Uh*{15B=TM767zbgf?1nah#oI(oHkQ~T&m&{c8Cr5zwc|FC3dvgBx(f1|( z#IFE^P6bN6vI%#cqRVC6k1J-PhjH9~?i_^YdZ!=yl_6RD4 zr=7-9RR$Q*+~6*~&gZx0VyV)$GO!ofX*4g|wNGhfp2h2g<(Yqt zG(CX(u}FeHqz=7q9S^)6YKEO@Y>kUn!|SDjx=5Gz_tD9X#tn-A8OJf+ zVpt;_XeA^Hv>qlrxuZ=NU$`zaR6ZN>>D{9Yj|(S11kj3S(CMLYxT-lrgzb4s#OxYDLX` z=KVQhrPXL1wjEGF{|BgHJFRZXb#52uthm49k-jmAq$wqV7P|KS0z8XV`u`Gg--{V3 zs*{xu|53UAlkty;sL^bHGY2+V^!q^RPq-~-^u0`**6sJcCm_Nec>5RNm(c$vcZmMe zef3ktlT--IF&UPoq6N+(gAff~k?3lB&D*u-upljbotS><2wBp>&_s)$%_g?uyOo@Y z7wP-%gt6Wxw^E*)Of>9;>DnxsKc3<063>Wa#08fR(WbvCsM2bF;FA(I!gv!+YJb!q zBN*K<1AU|mnC}6cj~nyrEK%5rzCI_!7^Itv3#ST1P%)z5{@SfkW|lZ?iD^-*Y>IBf z&ow=$)}9f*uKH25@cZk850$>^&XSfork(dBS5}@|8(47k^nQ>o{!;CSntI9n$a_Q) z3^F}}wz2VJ$_c2ZQ5Fp@_L@tP4Xb6sV`SGu%E{2hk+O!csyvS?SdzPw( z5P+KN5R>W2ZV;&o@4BvJ>+CWvP!5dT>bfg)3~sS|vwQ?scz(U0prt+n=juRiTaNo^C(O$D?poS>OF+KI~QS1ym7XJQ1faHgYhS8LH^Lc=ea^B&E7 z72xIB?{r|cQ!acVq$vAJB0xguTd%4PJLyE(&M7vqoB^4=X{{TnL) zmi{ZC{~MTgg3|uGAoJ>99~dCD7RufSCZ%tc=8;|EtNZ^&;T_O#P7m4ve?~HM<>xo!&#W1kjEzs|xt_no zfmMCfn}1Hj=v|)k-51v=B>SC=VV#&8B*Wm@whx81MujVtkbBu#(lMdM;jacXU1YL+ z);Wv|xLpIe$Co0iRE=zUDc$d%<{HoSVpWGo4Eg4W<9SH+0I10Z_9TJ5K*+i_LA~1E zr&pw-QW@8 zV7voC?T_!C8_PvUw{7ZiWjJQ9Dly|_(1paowRxk88vL;)jJCzkEC@);qN$SVY4;%{L|_^>miN&!4~15onFkt zZu~>m7%Qs|-1S|0-W3q&*F;Z_$(r#%S=*zks|t3PtQgcnJ3kEPI{w=BrIOx(z8Bko z&Z{?{ELMe#e=W1wm8Jc9BJZXEnPjdsJ{@ol{p*AXZ1VKG~BVfbhe1l^lE5 z=tODao}~u~@#?3iRi((={f)cDYp6GCe%?|9W75^ZR`&3;|IYmb>7siQv8_x_41QYb zP6DKlHvkPGXQWg?xj!s#Y)$r?blLlFL67og18)r*Z`ur*O4@ZuzXkNrx&5yh+^77< zheI#Kw$aQiY%z(o7{>Hqw6V*z9o}p5?vk=7WsEN=hOpm67yeX@5b zfJ=HY{{5zl0mP<-DKTs9&Dy(0JL2;uv@3Wy%ich+Y@<;^#{zhp8mWI)CPl~k$ipBN zTnt#CD`R$Ziz!26AvEaQ=^XmJvs{li*yT=TMXbx9w8#-Pv2A{0(T8*5mO_uqS)fC- z8MSEHs;#>}@3V4*5iFelnD@GG=Wb&7RSQJUoSQ#MYCvr4ZCMzp{gUw3K^pn>#MQP@ zOzbzmP1$eCV-x50wvQp*zbPmkH(k9UhJ0;dtUGWZkhq6t8QBZwH0|}~ zHK{NQw)ZjN@tWDZyL^2`)zjoPznVexN?&~69o?+E4c?jL-9_;GLpK6RAD@zll+IzZ95 z-B3rkUOp1rNAdHk2|GqFXRxyTEFJ2NI%yZa2oaRF>7F%~a1`|)7z|P#j7{zTvr_c! zy5YttoC$E=N{A)-KP?0?>MYtzd>DO@3%*Kb(htQwd=e*YresFABnx6930zG&lBwMF z5l(ZlOuT$$yp_8$^hF5cgItQUx_ak^ldxeeMfM5Xt!C0g0#|=iSg&H=^t@N=c=%po z=YrFk9NHG0)pGL-&xubVF$81qCBFx@?Gp)28zVj#mMXQpbMpSiaf;qv@xeEeyyJo6 zZI07b=VdbG&|b@HNFO9-q3?TRQ*45=rFOAtqJ`nxR;IB1V_E5SqYh$$p8aO*0e7rl zz;B8-fZC2R+q=jVnK&uYYCt?p9iP=2K1UPISzB_NumrHNaT)T%t>YGnAy(OU(cf#S za(}HQJdE>jY_u?wDyq=vd4*bY%{NFe^G=R$v1eK5XHI?2&#Iq5x^6RCJ5*I6z z)LgK?PDWZ2?aOTMl>}?n^%e&S=1Tpo&su2mFEg8v{=Z@l4xia`{ReP^{w7F_4hP%S z`>|l83ETcYJS{U8;5mzw@a#1Yi`Kwg3;z72)6^)T-0sePOcM>SP{{k)A>k_U^8wAY zY_Bu6Gtf{*uex z0a6tpYO<_7moyZ|tsrUdGH2F*_l$@uzPBn{85GFPz?snRtS)7=&IS!j*>cb6F6lJ z>W8W^g&5 zqBuEl(65(2SKJ7G*C=3PZEtm3>%ERQR#Q{n@zi9}=asXY8**f%{-KW#(Ph@Q4SEJq z<>fY1D`s7Y2ySMvyy2+b)Ro6~b8y-ScC&QMjpuqM!l%*Ki-JC(RdJl+wPn)*g1C$y z|9RZ@!HYNBK7~7Oj^(4{TM=CXTBpoZH#d7j&*l3=F~#EXL4(JPHo{D2cIva<8rsY4 zDAv#Zrs($C+OjYSpWWmVqqk$T`EV|tcgQiV!dTJd`Th5(T&AP#;#;5!r8?2M)bfw+ z93Yh5Z;ExuDy5GT0(FQie^=+Sn!8f6JhlOCI|&=fC^ym9WSR&o>M!u6pQA*u1QquL21tAUeDl04`NJVY z!mrb$eZgW3gWb2%=bOwgU!`;j&72B7GG^YZtF(o8x1IUQ|LLhsr7qM(d!IyacLHSJ zQStTLY2<6(Kmot6d-@Pauu+F=j7rsc>IEAO6lc_yqU8BMZK>h3k{DK$nbI}R3A`8T zbg~~y*?XB#?ZF`yEJ<7T4(4)8BB`=lX^qTP{`2%J@Kx@}Z8W(Yz7DB}4_n96SwUlb z{OadNzr#k;=$>XG@Qs{BQv-KUVJ{u3vFFg{e=Qo8nJw9VY zfb3%fRK5d=Mr%S{ijCoau_k!-e{)6skMGO#mL1#3Nj&+~Mre^LzPVA1m|TlT+f?l? zawnnc#ueV}p}C2gc9lMKDRU6#I4t)2o%SXn4dwP5`{xo?Fnq-H-3Bs4HCEX0?rVnm z(1-71x(6OwJmFK$%?980pd}Dh09>tmWk_qeNM&$Am{A2~`ZyLbo%NHQ-A3}NV z*OQoC*PDw1H@(Z*w5}LfPy@qIcXwq^_rQ(e-%v+KiR5F@EF?EqTCV=u>IJhi&ZV8E z7y70^Z}FbqLJQOE4%Ki!C7xAFp8BXKz83dp1?=z^2h|_1&&!EG-h1sl_5Wc5};NV2dznsZ2RDM2YVj9UtJTkjU+ zOknpt29(yCRNafY;WoIdlW@f4%UefZe9Y%CZ;4lZ4v*=+?c8-a&EUNp^@j5bw#u+& z_KVGGml;d!{G^sa5vQmp_1Knvm+P(bFRwJ^ENUMBkq#`0oK_(TU2Qy$_)&hsk#iXF z_E2{^PHPR;n8aZbzyCJ>ma678pXPr)D)*evrAnCtG@rG8o(=!%y5k3n*4+wleH^=vWwMEWzsdI!le0YUw<~mbh^d9DbvY zCCZ|A0hI(lX&TB|G!iUcK7XiCH5^qQzfQn?wlXnXGX(nN-mD<0k$)IwA(VRRH2vqe zc-MFm@~0jzNhlZ1lX=%ny?-#Thl%H}4D~kcU%blHzxqF&UUS4(sd(fdf4BeRZMx-@ zshFLho9dsrcd|>zFOv0giUqK4S%VzIBh>t;*0vi0WuS-%ZNNp**ge+Fj`rY zA+jC&E(uw1Us2u$Q;(00RV}Pkb61Z1ru2LON&nc=XckO0Mto~&vO<2DV^|%v>NgXy zW5xZ3s#ClbdGDC9vH$5Oirbj2*8WnE-~7 z<@LKhH2X>$gRa4e1&fun$&K2LF>(!?M_9)L-hWwggMy^1G&XRrV2q=75ZA!%au_Ue zR`amOb1D&0Ici`YR;UEG;Q)USQ4IQ-(tR;XAKUJyn2yal8Bl}SzSXMN2!iw}4!t?6V11-|iJ#eI{muqWB(mA8pGGS$BE zBZ=ROeF2{G@|B!Vo!6Xt~&W;kPMAqauWw#vZsr=n!gm5O(X=%SB9o$7RYN~^X@aP z^aMI@T#!}Mot4Sb{5I};>sm>P>ba|K2e=F=gFXdkF?o|f-r;A)(|Ey`N3-Ir}=AN+<=%KjAO%-onP)U4%nxNix0Jc41hv|DV|8Xm)MHzGo@ zEq#nVbpZqK+~_X#GzJ}4Of_uThE3YUN!&5m^+08LmEz@C$u|($>&54j=1+E`PlYz= zX-wkx&%J3{cyCKSj{sgY3K+wwz7V(IC2(nIDYbS17;#yx1AcK^q&ZcP!mBBjbZh!w z7>_o9^7sT9{OR|Pexu7`n=>rDqc%H@FQOJaw@lATyjz~k`vhNVQ46xS2pFjZYzRF*Hzux{5JF~}~4$$oGop3~@=Xto`ut$@iL?;UY)%;-$-zHK>o7Cqx z1mBVZ%0#l49OeB^L-O4h!lh(ry)Cjkm~&oG?GwX&zocA{YCYXre9t6f{tC<_uwU8eJnwvG`qW|7OT|mfRY1^%1IlwU zpGR7!t8=)r7^HC7Lf5{+LKXb#0)mx6l{=46n5aWYjg}SAqN@eQP~J( zAgVto87_0YFa-5`T=ipk|JUp6vcL_n?WOA{lG&rty;gD0(hNeq4J@A%*j0!{g;}*w zS})BkJMmf<)pyd0w{`S=w&m-pS33b0^#ongxq+LAjoxcc(q>UkGd%GQG(&^kH2J~Z_{?M)Ca#NGTHp(m2GB@m5_ z{h%D$A$LH}L~_K!eb`B|1ga)8A%h~4QPoh<-asBa3fBV{UZ{_?A7xgH>!=KP#8VCT z&T#gNT*i|D6=r;IoShOE;`Ht0>k|#kp!E95T&6?;9n<|wF|A)ViR zfLG^vM7uoBeM2Fqs@A9!)!Gidb*7yjM|4{4CO2s+5;IX|Lw3 zwCP%UPMgi7s2k2Wp7>O$*X!U0_pa==TwB#?glipplQTkgb~y}LvR8y`dN;*NxN2d) z?&j)wnf5NM%bwXTc52P2I{E2$EkEaoc;zqKokav6mQs=oTczaYv4u|@pd78#H&AY7 z;ig_Px}hn9`^aGaP|qSN*R^j3wu_y!iLuWmsS}6X6g-!PUi25=cokvLQgS{7`CVhF zUS)4m39C6&^tRyI&Sv49#tZ0HrUR4u45b(MT#d%I(oNDkwfo&tr+mI@8ZFVXpcoHU zufgVqHduDfzKx3Zh+1`(P}R1IUV zrKSUR8bMtNt!67<{X(vZpc*k=1H~803G(VCI5wI%AV1nhwQ;aE5#A@gg}E3sMNf@r z;F1=x&2_L!<@2fu+(qX%&(Is zZ*<hmK6aMAcgvB+T_a9)$wa-#gRQw zCB!M=4u*D{Dx4j{{wxu#X||*JkQS ze!z9z(aoVcMP8~iF7UfFH}lFHWjlYquX@G7rKe&UDE4Wu-AkRyKdExO_y+9D86Q0n zIy$owbV%sV&A?grPoN*z;$O?f=bC?lvSC9&$3enSBZxU|#IoPK#Wrj6j_(!m$X~8E zj+b*BHuB=8V-rSj028P4E>71q<#QFZDB6^)-tQ4xki8mL0maGQf*)kxQLUZ#Duy`F zyWlFEg&LIZXgb2h{Bpvim2c);O*+%>CW4VJtWa*rhQ&6 zFhuQ)6CjF@n-Wqn&&cfv6)gkFEE8! z!Ux2?Sap#cPwOyZHQ3VezF?PpTRg{Sn@~bHIv>k>^&Y8WOza{0sI=c%ust6-R*fW` zsQ;$$3Idk`Ef7Zs;p8KxU8>2rzg)d`#)SvNc3NDh5WZoS1rq+=)%QcSkL(A1_2;Ls zjKayzPGW;dAf~OLh~~Fy30tp7{%IOtznPzljsP0au|<)iPYC+X9w7OauO`MnjXp8~ zwP6<}OQOY`d><`IlJL49=X+L9QoodHz~W`1rMky@d3dl7PbD7Zzb}{(GU*_{1?Oa; zP<9lA7(GsU&8hc%XuLt;ZlRg#?4(}fU~`XBxs&x`g&cL1*A!`aulPi#G+ck+?Kn?r zd4*pg&@jR+=}%G<+AO*L)a6I7B9ace3%>nxiOD;}-Y~g{-RlULErD_{v$(=rQx=i? zjFnZ-hV?wi$yD8JMDHf>y3awS5v3+^+C=TyOW7A1as@pd_Xt+8QYSSq6hyBo)RwB_u9yx!3q>ae{? zk_-B3;@vw^h_jNbe~5#Z)+#Acc27s;MCp`YfT6w}NZ(K6(I)L^suQLh65(&Yn}cwF zd$Osh(!d%Eio_U1hXoRt=3cCxW~@0M*EA$ssf{OZ5}+dpRFPAe{;O7=k>@%3W{@ ztgOA*wh5>6(c=+i(LDc7+ahNlD9aJ~2QD}-fK*J7413%eq#O7zuM%xE znKI>;-xA6`f?Df!8|Dn3kOrat0B0WmsPD`zt$JO^E#$&PeTHHnnQ;jp*94+lzjSt@ ztmLWLrj1Z@(6x&DisA`}ijt<)gI&UMh>3-Qw|%*L=#Tp-=BF^^#f?`*MIl#LS>DAC zN`VAetPhS*oS)oaZ~|fe8UIo2gy1a z4}McjA^heA`fsI&QF@yiv3Rn4>b+S)XsXOA?#omgp}0&TcecPX^5E`oiV654R6(Fs zL=?{Sl+U>1G}zTiI(sw2t<#F3XHU2-d<$h@u~`|kDGgCVDX+g)^`W2XpT+{Hokm~VeSW5QA77tthZOYyxZmZq#{0t+Ybs0%y6-U~Aov zLh72s8HpkptKSel$SbNB&DKwXV`9yds`+}#tWw(sF+cG8UrUFq1OgM6;cYpqP!ZC# zq0Mat`mBP7g;+^l=lgtH$pNr+=^?2_{dAlH9aX1Ly?pMZiI|K#hnT9c6knVwG4A_c z2C+Gmu0?wWPu?FcDEJ4G=wHwa;@&OGb{f5DOb$H4eu7!D4D63vJeZoJ)GQZrfeEjq zYFQ~>*qY(GFTGvqq3GXI_>IPHm*);ha7~?QzWznIdei;)c@6C94tscMQ&Y+29ziu7 z7olt~D8ACD9z!gDiTjfBil8EryLug^UzE~Fe6xza|Nn>W;yx4mAqt&@_ zg{9h2qCL(#rZvrp`cqMcJCyno?tMwy%UK-UY5emh4s`X|R!U3Ayq6yLpVAH4k-TswY02EYs4D3=`M@HgT zRm--*-)S;FG`X_)^ela@6e(zqBpS;ib8|`?0c3ZbGqzGtvlie#g_TDpq%!nO5)!Y zpN}91L4@$;dK#i%V+2A=$GNSklKD6ZSAO81-d5CiEy5eMkxS5sdZk7$$(XM>_F**o z9UDX`KOJL0tRwUyFO$yV55s-f9iZctmSQONp|T#GS1B7mM))+yqrzzycQme)7E*}5 zY)sCO+qICN3k+4TN6vyi`p^}x^MVCXFoN(2STLNBxGA?~RC=h^{7 zvsFXc!^Mvndf8;6U(#MvQ?;h_V|w+h=zv^|JH0THjM{&RS_>~0MEB`kCaDsqfkG1p z{rgz5w8hmY_(kj|AliI-HdOSo8sn$!$y5Tejb|HUZNba(UquNq96cvnn&}XC30-rx zANIGo5N^#fQ>>_2tly?|O_$upi@(GM?J)F%N+6M?nCEYYRNP(of7xDdix2`5LJ6ghkZ<-f z9>xVTG_+I(uNqu(nl8V8$#MOsoZOl`q%C2vMIhj9fm|QkTb2z)z)u zvReNmhpet-uQU6N^d;s?I;vMh_Hd#zyayO3m&rWQVe6J_acacl4}`Wh9k|!ak!T}A z2DH&RYRr^j5AhKwXtw1kUArGgzFj%^x_(55cFASDxAInsP~?d47GMAK5j5Q@rhoK) zN{vXm>N$KbnEK#FTty{(1Yl+=nZDMe#sO_%dtc(n6W+9hif!vaUy$6@DZQCKN~W232PQsIfm2{D_fhI5`4m4Z9d-}785D@Dx)_1g|S;a zOid2`wRylfOG|uuiqu#Cb1vhu8jlOEpA@cwh7Q`Es3khyTGKzb&jDJr1ZLKp;qB(| zWZQ#NuZ=opUr#XjIuRC_wmdY2@nm6dUB)f$l;Py>-3~v92`BA?B7p!8E-OSX=aRyS zkOWVDK+WtwS<$ClJK8-6sM)EdDQHWH{pcehXL<A*q|K z2K`V+b{o?}$B+gn1)qj%va5h&`r!3VtdcLp;bdN|?t7qiMM$UQH?F{XrI=MG<`~mG z1*J<^T2?T)w@pRWfIL_NfON(Vcvk(7+dnGZ{9AL%KX3CI(*7xM;x;$};Ztcwx{0IQ zV88NTdfXeLal4-jtWLDr$R6Q2raonYm78$JYnFNZ#Bwm``{%eNU6aP@I~IUGwL%z^V!IavHgR6#eS!OS6^Z zk8*nw7T`Vf_cniEnjw&i)xi_QalZubhjcI7xFn@GUqVOtT>Oe{wG^};zrtTf{%tGR`UcGpvQ-O=pWeGzhM#TdS7IX*M} z2`3OFC3PbI6+U0)o3epR?5UU5GAb5PAazft;z2j_|AkS?G<-^wR@6{g>`uKNdzcmQ4hqa+kv0% zlX??p;mtHa{)x(bm%Y0#$mBJ5aIu@PT~^(N15lAu%AMgY=~GC9i+Q_s0*qam_i9w{ zP}K{cszOC|<*I(%;H}p7{Q@CJzqE!svA`quRPcN(RVnKui0>&)3cg!Z^z@ji%7s+W z?|<=@R+-22j>5gK)x`{reb&~*=^droLG?I7VDsnGO_?6d*B3&=uqEUtOOYykPKcLk z;i_T2MMsuN=H(}MrfeH#LO4V{u>JRJ3MfYtZC!;ky!u-=-}~$e3hYboR8{N6GToDk zn}|FXHTxW#tR?hz{A8iWV;Vm>Rx!eGsZnnSgocm)fLGvh`Gj?aG`U zLA%TB+2IaJM=vuy>zLv%pr0#OS;l<_nOH!*&M*dh7zz9S_qbKVi(wv;BI zn~vi?dGXQ~$Gslvpd5DocK_1T5e~_BGv}cCh?Ij~3;u&niNc(;{kEJsck9KG!dN$k zBR?^Aw92Fg+U;C$lvCoQPhjWLnCsmKZ;gW>NSQ5QsN?Qy`MGMQsjoRoj?I#108Ony zfZ#q>u(5rW7O`09Ds4maIv3}zzrzEUx1=&kXlDD^=PBvy;}<4%-6dj)^P@2 z9E^<8Ay%BNrkJSH)GeOc{8DS!~3h(&t}YJe(-Ul5U?E z5EL=>UW>~F&VV!_)MJiRC*W9zwV0Lm1&3j7SJ`lxRPu4X@oHiKg4F~ub~9~_jVk!< z2de02+t$KnTBNv-qE7_REiUY@hn2^8nI#@TyW^&?Ya6c5c76?oj~e$!4|Qk?kz)Fs zI0Y9t!Y=05JC<>{`-NMnk2`{wQ%Rv-9fvvJR!qYWLO%heEHhRhH)1eNC`#DbriL*` zKox7W&URydQ@A6K$IvQ&IEtmt|6uMt!53F75~T{Eh%}LA1rY)1orv@j z5Ro2;f)wdRK#D{Kq!a0#&=C+q73qW)ItevEh-Wz0TywhKch7g94`-iie+V$H!IRPM zr;NM&f8Ni#GMBGa_{^pOWijx7&sf?g*;c@9Rb7C$l-&HKg!;c6>l@^xw{zMXTz-~?G`h`mGcg$KR-tO>!gZw~Ln^PC%Y#skx%q3S^k@_Tu*DZ>cJl(4uW;hRG zU$KxOc-gq{-D^Nqe_@mPswN>a_@ayA3(}RpwMIj8+}!NYLa?KQIa}@Fpj(0}l7yBy zCSLkr?f+vbmULZtPkMLHhp{!{5@T!S%$Tp`_J+v(_B@?&7+qV2mO#VZzx$iplD^*B z!v}lU738yngXLV}AlG3MWw$I|56{*N>D_7+o9tRu4IPUz!F-;B=07LHaIjSK)}pm;$miF_3{0(^h@}U3=cXl z+pQSMG;#yNeNHWn^n@s=LRi|U%! zyj}zs&)2-ou}wpFEpYWqxg>O<~Rc;1Xji<{X+J|<|-(MAc+w;$cx z-l!U+9Gnoi!D*fNjwA?50{4H*Z5^w9X5dzKyou6n|LUgiU+(lhadEI7t!z1wpGqh<>W5a zjUNhX*WFa@?6LpwuG2x}`+7Gu&Fzq!Hd>!&bqoAyw(Gg* z4^*cbz1Rb_!wcwBwYGkeg(%H~d(D=X^}efhK^lrk@K>9@^anpYE>1=BCM>vqT!vFv zAT4P3C$tWim3b}dK06s0n!qlUx4K_NQ{~R??;$ff?mB?%lJ%y~6wMHQdr9+f;X~|y z#;*O^r?YMLjZwZz^PWnGhdB6u3Tw9b+WjU90H|prB?-Z^m*5>8qsNS$Cg`AhLL%<; z{LX0`)M7LBuA(k9*XI|!yRUUE;A0+rO1S&z(3Wv5wST#)@k~M+Tcril5VZUTOv2Sp zV4{d){=VqdM&oQlMt6~Kw8?aZ;Vf@MECC)ytC;NcOvmq)9T z46iAE&$EI{noSl>Oy0h_!}osrwv;+o*q~C!<7d)#C+}zUONOP)@3vLdy1f7F$e};_ z+EBw<6}M}0KizZSENnOKQkJWH9}_sUMM(KryEPPk-;rJF8l4)68E$XSkC)sANqOj=o*~F!YDklOuXG&$CoNF z4HuU^Nu0wQB4Rva1uF)H>#Xg@$ZfSVe4^V(gi zwgy3hm&0cZ`OT0z#5k{JMMeJ$o07mAEX7MtOL89@XZA>Rx<~sviDR;J67ZlqPtI_* z;?)j6gC~^u2o{}fjoeAW&M@13n12aQCIq?dLzre9Y5)Ngq?%jI z!60wya?Zn%De=Y89Uwg@q>_gq9ad431_8p}yadDxIr)iIr!w4&nfjV4#g;F`8_Ipv zh1k?(n1pO%0T1?+zRii`33z_3pc#>av2lEpfw<3X80-Isvc1VR1`4&Qc0IJsBI)B% z9f}q$<}6ZopNDEEZFlQ31i(deC;}8E+x^YwQtFF@Vm%TQ;S8w3MlwR_`V4D%n#E9d zxD{zy7XI*vD=;uoy)pHqvjZO@+7c?fmNV@OY1Lvhx6inaZ>eYGx?pi7I6Stv(43?@ z!x`cRak!PCC((J*PO;6hAmes;fV<~2#S_yiz3$PTYUm-51*l|-_|`DcKmLrlR17Fj z&a47OQa*OIz)!MYAL#*Wo#^X@XL*M?2)eU-FU#<*F?WK(Dk#pPAxUaZD>3YjUdczz zxQ+TPR|i)b_2*BY#(*C_cyK_+@|ZcPnR0<{Ub;m#xcmo2@23u_wbrjmB2hrGXi)7eH7OHIjOCr8G>l0(0+o(g(>9DSB(}~+I`H+P{ z)a<4=s^j>^Jl-{MHq4Uc^+T!y1HC34!gN_f+uRv~ds}(y|*R(QfO8Dg*W`ux5vvt``JXj7*sz|3` z=ErvqGdto`-V2tzM)=1FfR|@N8zuW;s-I1PGQZ~d1I>zHyU0u-v#Vx-DreCjk+cM? z!#*O6!_kU=cje~pp~AeGVGEq?2jPOTznuw_bY-T?fKb%kb89@?&sE9nl)D?)G5ThF zqO~S)2ya{VI|UgV-84)>nQPAO*q-Vu7{qTbO0}(W)KsBJfH2Yg<;lAa71QAb59IwW zWSX+w*itI|g2HTpS=VW_V%xMO6&{&Y(E3g2s=k{ABwneCzpcBHLz=%1wS?Bj4U;?* zm@-P@5piEn=v_xyW>?BsdTSJEz7SOyw~N0wy3|8u{3}@vKflwy&k|Q{$UoOJM4xYR zr8#}!Cs{3O&Z!6~iP!7U(CZxMd#ub2FM45_>689$Yb`;1mqj1jgE2PjsQUto+#)9ENMOJbob6)Og%tT-$&{Az_ICe zJA5?zB{~&niRk2}yJ>97$6kBzyyac(`>>UL%lm+=DeyUUK6O?>KRawQBmW8XoQvpiXeTnNy(4@iJ{2O)eMnC0nf@BD)E&Cbg`ZspLY9<)baTUhPFFP1T{MOj8p8OP%p>vQstkHZh&J5vyS z-v5A=*&iw$@< zUBb!ohD^d?c-KkBh60k=@%p@r)H1-oOLQjPC;%}+hYUx{5%gvWRS$>uoE+Q^-m1w( za{FPbk(xNFKs#J=#NLds5WFm)$L@6D;A{$|L&$8>;H-Zo+0<;A zV|rfwg43GaPqLTdBXqdM%9%)#DB@!8`;X}3W;h{rn9v>E$UW12bE3=jD)3L=Q1cdP ziyd6u`5%9fnNsjEq$oOt5)h7~D8`CqUe2`j!dY@e^eG&rdREiK%uQo;xbbOK+{u^ifeHY?yxsWEv*DqnGvsA{YEK zADe!^ z8Ie{)pO5bc*H29`BZ}pa?>kg&{fkXS=gfi1yVrYvD4_}x7U3uFafr6EGtKeCZOR)3 zlq40@4H&hztMrt-y6d4gYUma_=^}d>aczrn++>X;+TM|xL+>G7&HLlq2e=7A7X$qa zkl)7@Yq;({Ux+zcDuieIk1{rka4isLCgTpp*@vHhTWonLUEPX(ERH zB(tca!PZNFlCxB1b_P;VX7Gp0PICoyy@)(arlUPj2KROHS1p{d(323$N^3((tGEnd zldIKIJ^>9`GAT-gQs|y>Ck*;uraxzJmhF><1@P< zC~jSKu-?^RaG3VJpmwAhSNK3}Ms(yg_$lyc^HUFv%^1WtoW*+PrL5FrbQGYA&H{k( z3Up)P^ht_`aqyNpG^d&a2E{^n^O4pinZ)(}ErYDaQe{9^5&$(M=x2|wK$u~6R#r@{ zPX=0pu`g{Nj$PmFS^nv9fTivh7qh)S~Qmse?8o^M`I#pq4T zOEo@nWE=*y**4HgE4v0Sx=bl;pd{Nn4UaOc&@3-DNhiR1V^NjPXR7x45$w4vFg9MBDuOqCIE#I=?+?j`lT~B$vC3j(b8`_csz$89D_&ewH zFBZ=)`QP3Dwfyh4)(55NKTBvSe*RM4PlVee0W&;TZ;2%68sQp~L19vgOcQ!HL*7ka zuE*`56V0Q zNWF#oJ7^rY8W31<9xpT=9_>L;OBd13rQq0_3uZW18%1%u8GQIxBQE^4wdFvxt;{a9 zLvB$^;8tYuPFP$ZGAUn$jpgVrMk_er0uB;hfnZ%em*yAsbVzfkjpn>)kw|&@i>j*1 zD3*I}LA)hg+fy%36?iAlqFR7b@MT5};=H#nZLi|i;)smR{ENo-<7zIviR{+Vs&@YE z7p)~3UWe!4Wlvm!_jO2>c39;=R_t887l{KfsqhNJ!FpN@)DwHJE=Dh7+SvLJ{!fLR zK*&AGUZ|^s3(JB?>>6&$Up5oHpN?Hc$|XObX57D9c&`yVp3tgTFAL`8~cb!9jB7 zBF6(`Zt0rp5UD4@>R@IndJ8~_mT?R{3lD#xNZaa*4U#(CMbouF%hx<2+qqc3F)NU% z7`_m%@M;@Vz09iP;G#qZlNkO+wzg z5wWL9o&a6Q=t}&m9IKB?hPWU=7uq=VvhFxLD|N}qjF5?|YtOiW$A<4c@Q4Y8Fsw_P zpW42pV)|6<_HepmU))W;ZB6JEgX>`4t2Ps%&ZHPS55oAmP-@-<2R3us(uhBB5ta*F(gBOvrjr4p3OyB1h?&M7`+a*6u_L z?sTz=%vU(uo&EIL*Rx+ubiUJo1AdYTB8yQW^EzgI28Xck8HkaXySVI={Q`_XNN;$4 z8!0ZbvGiUdssMn}g0{;z6d`Z8%y z_GYPgy8)0>8p)rZ2xLEn7c&|RNK=bV&$aZ9%P~Amx}}%VV4Cf#&!V?lUH1vB9XXQa z;}7t#WuJ^*le*i_40z-|TJ0fYfFmoaL-5M&mo7XEQ-8MN?(*t~;J5AS$C}UNxb~0( z9EYZ}HjU_T6!U^|Yc6>cX}3(;&nMuzW1@qn`i^QhR?b82>9yhM-Y#Y0>GaN!dWt!E zwmFMXD-YW_Q&)ObuE_c}e$^j6Oa6oIL+SJBhJ{Wh9?O;0L*h{Dhz$t^zmS$|tA@Nw z%^glt$4g}%P-$s-m6y2rw@OhYmM&e%M712=fsb)_qU7!{dcg@)Kv(X+f{RYevG@E^ zkFp6K`3&Z$4}B)*EQ>0FeZS6#`M0_;$F2%7XF7fQ zdR8$EY;hj1)!YTOoI|r8Vxl&p>Q9Nj6IxVf7p+sk+HY8p^usIcgcNO#%3-1B7KuOf zX`CK7Ex&~jDSk-P2lS{`gsR2fM2B2&_YT0NVOe!b)CB)2 z&HMCz?!~c?COL(rM(z^40n(it@oCDudp{QKVj%Opo1I_0nqp?D!ymlL7{O+t8Uv$j znuo4|j#uVQ27PpLq^X@e#GCEi2j&DVBJ*_(7M~Gq^7co^ff{Xu8XO28&*cS-$`X&% z4|4##vX1dLG0`gsx#@7Ygn`qXiL#z1AfH+Rya*}9lYli=yY_w!3Ofkt1t5EM_pfC5 z&C{+tG`+j;a7JC0U*7Fxm0&doW+&ZPcC@-2@})c7dhXHDeClyTd+FA&jsl*`YKJeC z0B>jWtVMSAvO2NH&t2NLv=Cs(aZy{a23!MsK9o?elkWk39ZVYc;Q@kU+@N@4X>Um= zuk+-T?ib|^!`zc%*Tdc99e{FMjXHa`cHg0-ML?NV`NVNo_;B6y0A10fGQ6pCY&NsA zBEIwsN&UBV7nBQm=$uPR$&FzpFbNfAt0`B=Th;y>W}T5mxSD+dbWa0Sw>8+J%7zp3s1pXKKE`ZQtO&hD}cqT zVn^HMeO#3Imh<>TqE6m>(|n;M#&v7??x4@Y4>~f)&|~m$Ir9>60P=NeZP{YCW@-FvPOO(jJqV?$G5~)yrM1rJ|Q( zk~WdLHjwGnl04X%Ck3~SJ&em(8FoKe-G%)2zztLE;}35ZmD#cT=a5c!?jcQ)>Fr2g z?1asBy~sb=jG@q^_TQG~BY^Z18Gru`VVAHKD`znY_icFpgGaLJJ|&{1UPtx1`~%+- z!JXnsj*+t7Z`q$zX*!9aXHmjHDRo7jbXoNlGo zLBkq$hJ|!Irxgh8B$ge&=){GQ0p*iHEdxHjIyLj(Y+YAQ0N1v8ZnIB7A->dT=7Rp= zPqK{?z&~WT;SNV-v)~O4L}b0AKI{Q zx$%W-uP+L>QeJw`NTjI`H5ky<9O)$tX{E0$W*uAYDAZ$ZiCD6Ibc3JA751Xs(PzF~ zKhmWf`2#}R8qeZvt3JT);9VO0vM2A_y_hw9uu@_6Xxa+OH#@u6?sxx7U0uqPs`9w0 zS~B3RIvnZt!k9VpWw-a`$RPcV^&+U`zI~G7lxL)EUBQw|=2HCV-R|ZEw~yQp6vbwy zH+^h#vSu8<@NLl6CWLehl<$+o5_?ve%9Ge6)STC2IP<7n&hk=vAbnAlraf{+F~stJ zxhr{LG~=2%xhhoKne_TyPBli|H1wvnFpYT>t;3OEg!F`{K>zr-iG#zl60E%1Rq8Im zJf(^~?!5UlWyW628tsI!@m_~f=99;#1R_Wt`BZ6!9VVWj`IV9xsS3mFqjt%DM-R4R~{g2Vhq_6{0G;8!0cu8Xowk* zHa0;%bg-_lsc0(hz{ZYf!5H zv6J@f|F-X<{MU~Q`srvqV6gX7=s}*s!hh=AI_$q)=-*%Pzv&>Ve{~T3xPmdbV{4ED z&m)uvN$V?d3Y?8p#1~h=>Dwz`Wj}&u*QlgAygh|)$r8IDNB%yVe4TtNd@w#CUVE|+ zDGpxxaTwI>dBCd7TJKvrQS}aaR+t7~x3t%(==8%yn%u!vbfk@;P-0V;hpnTXyvW~unpAnX zV2yYidv;%XW4=UeRmYs^IBrMI*0hK1Y-7>MMp?H9ghn<>6v~IEi*iod&K^E@hs=H| z0ONIe)0z7gnJ2c$rPV*z#3D*k`_$rsfwyfW<<6=3=cNfRdt$w3qrI2P3->OHCC1-f zFl*iJrF~y|Z$9^l&k^_Q=Qlo^jH}Jj-+~wgY!5w9GhVdNUVO&Zquak>mei?9Wg@J0 zRa9eMbviK<35kQ~R0SD)sTmSqpEh->9+zWITr_%eKrHA{FvXZl-X%B`o2=|}n>T-n z;z!VMK+4Ei5OjVFBOCf?LTT?FBdrswMDamJ-wXXceumS~kfN(y;FT9X@76^Gsbwn4 zAig)i$Tvp;X&BRjwTl{4(=o2rc5kBFK@R#8JMI|_-rOUr-)}~K-9LzMp6BFSZ3Kjr zXa}X)U5K>vYBtB4sgCp2=f9o{2y9#*OjpY`esELaJgAqv_*)MZ$HN}fGGf&yh1Egf zZryknl1QVz{a`;Wt;=H2fVFhCqch(Z-eAG_UvfgbTj1sPU_m%v-cc^^kzoj_OL^Nh z8VCTb`idqMCTTlWdLC4c7I^Gi z3H-=O;<1pVp}VIZyTDL!-BVZ?J8}~dUN8P>S+L!t18HaVsnAKNF=OsV(LL8dBvz7g zeC(oJGnysX9j}E+On%Kvc;z!UCBR7gO-~^IpkFkCRsNP~Ajy~yN9Iy**fSopA&2W! zJ3*AAIAN|s&L2lb${Q}|*5U9kZD}{upA8M(*nDY37vHud2^N2wZ#;G<35lrZ%q2?q zSBQs#E+|;ei8IU)Jb`lLX@L>xo+z0m+8D;=+WkBm_VOx+&dpcRr@h;d=5 zn#%U1sstAr24kNC!>Nli$sc5uBFs?lj3@YlPMr6j8(;jW-7rtXe6E^%Z%+Jzz2^*V zBh?DxyttJI!7Ja}lIX$!pRN0AdGjy|sd(b(+&EDb{%)a= zq=i!>$yR+mhU*Y=a6Kxx-sC6`IO__l68CVpXmO?@@%&hyb>9H<`kbt2P*kCNkfAgx z%;FSoWHa$IA)+nSCD{vkO+$&Z;HzakKKj~a!zVU^yyWDoicUMUO(t7_SAh|xs})9) z_v2K4U7M6SABQsD0^R}4z+%gYC(osHns4$gQMV$8f)PsT0z4JsGZOoCW)3}EZ#m|0%0yzoS?C=5e2YJTGrWHSXEJ~BNd67w;Aaou!z;yL)EPJE zpIUK9LhotUs)3Gk8_>)0sQ|tS5mD|+?>*Fh)c2*-)P#_V7YxQ-y!QchG?f(>Kc#YO z%VdTF@!0i(k?8pAmnIj^(HVQODOoNsxRoi5EGT*-Yrj?pu;7ZHr==@SsqYX|_g0GzC3mSW@!gM?p^GG^2KB#VPL5xIDv$vj$%q@UaIES@b}=EwY8|-7KFRiRm$ho?i-vKWZzNU{n@Ndthzmt_^|&*2u24=5 zu<51T4`mXRTx4u`RkpL%pYQ|ZBuLQgL{xqP$hLqV{?x>o+-J1-5@F@ zF3(D^I(@}U!g$_V*Q!Y$AkuGE1y>+x9DU*Y6?LXXJz25Io!>s>^~qb^SZaJpSb1TI zk9o}x+HS9(+z0Zn(n*P#_^sB|jLgqJ2#J*HXJV=!(#9`5TxPSMSQ|~nHp--A;|0>U zdGabs)NVMxN_)$$Ky&=i2muw=g-_QULSa-R4s$}PPR+=6QsnV*tNWYsatpkq;KFm| zyQX_sCC0kODK}@H$OS4;z4Be6^21Ho?;H?F#%R=M^cb#e>2r!_c=oRw*YYnKQGvg| zpN)fPPb)Vs`%f|>AH~qgy~6m$kc~0(4D)$f4CiW98{U;G6j0k`Bp6~*E%KZbKn!Pj z^l>xam+?MsLw$a$i%)6KH&GsqqKImQk0Jr^5UB}|+FF#Xr=)O+SbS`5M^HL|v;MekY#-}f~wU@gbro8QXzZXky(%M?|- zPh_mAzj9_m$WD2C08an{6c@}r+-v!~_K);yea5Bin;`0WE33jX1 z-s9A4|D(;Pl>Fxn`GcRL`X?aj*8kX+nf(7yQ$-XLzK^BzaJjw;j_#ZB^c1UZiP2eJQEP1}w4sL4p#|*Pz2bTN@%@V8_&YJyg}= zE|@Nm@gqy{+$AL_N#kW?e#uoZaHXE;2^p5+2l63kumYny(!l~r#AWQO>p-)dE~yr)Jf z_=l*!Lw4)F|IKl+)d)l$yY#ksxtAe|vj}rO&w2nKg{AQCxH%uKSg`iwVEz@LV6qE@ zaquj~PNG7cJ;Xj2P}CIQGxFP2-xV9s`vbG{Z&UjNv-9uA2<}vht-JpR8wc|{ChXs% z_6OQ>{eK~RfLz6y)_)Vm{_N9a|HqnE%#%dQWs=!mGA7-#gAmSP_mH~3=q`Vrq@{O| zROp&x6SjrdUzAmS(BI#KCpYKc-{1?OBy=DPMf8XK+J2bAx;^`5xz=ef=hng3dFBomf???a^M7 z(ZD@X&Ig2;{K-NUdPkWg(PDMs%XZFz4bPocOADWByKRm%?j3Y z$hJX(lebvC-@Htp*Do2k8HqTEy0@mQxUK{ot;dV!8tp()>`@~Dn4wxGO|QZ^i7wvF zbdP3afmB4ngumuEL`aDMT4Pk1KW^OXP1h-(ge5OTZ?YqMRU}EfsNK(g_y5rh8_kXf zH*B2TeK<6Fjy^(;*J9QT{$r@IaK}@$57@_K*&CJw*NocPf1qi9B~iRI=^4q8SV7~W ztHwpB9mvt>)||n;fV`OlomciLCJ0QFtu_N*4YPTHhMe1>eIrH5rIlO93$~5^c-t~) zF6<62DaKVq$9!e9w0-~_ZzX!h&~02I?rVqBatw9E(s0IYI=i083~R-&pedvmr}tp+ zv2rg$C~@37H41(m@?16Vf3#C9W7+>`$X8Eo{Ogwdxy1Mbs`qEleEGj?>4T0ck65a! zz%#t3Fz56hrwxm>Re2NkpOH4w0;EB zwJ_(VJl}@dS)O=#R#E-jXjomX_RVIw3BAr+e=m*x zI&TDtrxN)lQQfQ~ghOiUY4OJo_P&J?VtF|eQ?<`HjN-l?v7RaCsjLblhf+Fm3Cp~G z%yMg&%q=|hw{_OHJal!j3|u z(L%gi##F)T7HtpK+et0?c;6Gd6Xmpsj4B0)+|pUGr)61FeJ(RSXH{8gB04RjDJCbC zgUZjbUN`BWJ4N6VCQpa%BR_o;!{HK0<*M!0-=k&9c?#oyl1*fj>}m+lpB#w}3l;*t z1_5CHRTzyA_|KQJ;is%*6i-y_B&22r3hh7?ik@xx9My z)0dlpe}GH@E>f;dRiJ+(%t@d%agw}wk3FxT59WurYl6^WhoCTlP_sYUj> z-*|JG@rvSuaH-orPM@kzvpD%2K;`YK(qDf&m+(ml2v7hjODE}-U(C#dtj=qT4u6`K zqhrOho>H?p8>V?ND9-#KlEmjN*u>2WVJBqjsrw5U1m56#!@am^U32A0^z>Dhg;X^) zawch8m!|$*N>44QE8iWeHzv{@%(=o6L(%EFK;5FT#XUp&KD}55Mxd6QZdlnNCJ-o( zeu21%p5qlm6!o|RvB$BgNehKa<6{%)^lJ^>oX{Nf49B6-;XYoMkO07=_%Uiy9^YZQ zWHIJtp*mHmXFu0enbL-yZ}(E@=k0WL<&7%JKl~RpPnCV87zWzlr1~Q5-05H^0s9*apl8@n)xnqseR^QC6sHi=z@U;bia~Jt9 z9y!FU{Ma@{>WR%;S4jSj$v|RON{9eLibKhi&{WsR z>=OzRom1NH7-XO6mo#_y&DA^2p`(xr@*b8x*1T5myt|ImPrjZ@58~FLSs&Y*5&{h(a5qPl&nq}ew5*z}Ac4l?oFR1T;&tEpDXp&V2Kw~veN>D| zdT5+YW;1~;HuWgF5lVQ{=n90n*e5-%jX4YiSf)0{7sEzKc(JYkRS09}!S!Sxb-+#M zv={l`S2X~b-#wvS9NNEhWP&qIKwQ@8> z^1euBb^jEjGZ1^)pL4w4{c+W?==wf3%jMRQClLH;8ZO%%#_yQWsE^*A1InMi)p}<> z1{jq|-{nKA)%1X9QTM3nkeG*hgTNrh;#lkKkcwoj@--Xkjb5KK!I&a&i!#f`ZZA8x zydS{VIqNy;#TnH}HPr7}2qAYYa>Ez244D z%~D9WwZ}^aF$M4IoK6~|jquK~xEId3!=m^+gKd~Mwcn`jsge7uRn&>&>e}4u-6RcA zt~Q{7dKnq5B<}o}z{P@hAejv4=OI)56fo>El-aciy(I_%b z2zOhG;$7EVOQ&eaN?_j@Y-j|1>@{xeBHaXmJB*NaA>mtBPr7Dyg_pNEXU4D3-3rjF zsRkWvvT73xwm?*>JLc*n;PyyD5X!V-(G~dDYp-bd4<=k5%RVluwu+v=fgDgis~SO_ zMIs`;(rnK0_w;ZNJlH1i@8qF>$uUxTyakdlQ;yC7PS;;4)Bo*bnChL;WCHQQN2{^Zzod(ya+L8jX>Txf7?(W32B3Dc?SO=~jwPyVRs#vd1qj4=x{!iPkB1IuL;|=U) z4LSoWwB6?+A9+CxdoK_&% z`Cu5C2(^8EXxJ+O2fDzkANkbWnewXR&z7o?-5PuB<1cvZ^^j1l>>$5Iv*s{cx5d1= z#l`!u)?bCzFN&#CE8;O!j#t((LCcQEofQ`kE)9OFx}xXl8LOfA?Oc|-S?pkKF8vjK zn(VI&v1AmAR4h-CX?`B4dDm^0B*Z8j5NLv3u$n^$Uz;JI+NaNqiWSxSV2WJmZ*~l6 zB<;`jE$x^NOP`fGepfU?>ib1OOt@+^l4;|qQ;k%KCvB-a2rRCk%J~cLaf9) zpBAiIXYKPs=(26qgS*l_CTZ2#aZe3wEN<~VMcoswXZ5Tsk{oY|t!OMb^at?ZLTX_`b51j?5k{iB z1!?b923!}0IKDd+UWqE^Vf)mfBilif0805%#RUo_3eBT}5wtMFS@Z>hpwY00>l+Z` zdU=EJba#vTk6DzU_TA6s>NMpBjam~tPj^@%T!<1s?g!Ki=<=mAb58`om!xICVMo?> zfTzYw+foaijskL#R8a|iH6>+LfyT-xKJEOn06yD#3e2Rt@~>2+uH>GR=^(^g8Tf$d z_r~|g)Bp}Z0iy$E2}m&dQjy{t%oY|VY@daPtAXwwvd!%Lg|0gO6EkR-n|C$yH-g}{ zI12kOaGh^B*+1_17lcrG@Gl5q&A#8z_hrzrt#Zfv-#9GgG6uk$v87_4tfiv^TP#M`ET{Z`2q} zqQZ`C>iTXM??>{xroxxJ4_fIhW^NOnz;1iVeBCWlOBb8myngyl4OdiiALA__>0J>E z@PKu-I^*^Gs8|~)ou&)p;5BMx?YJ$-We4{}0)3GRqw;tOV^bJYAyQMnc`-T`M^ zD_|Vs3z;gqvn5_s?QoEu6@+?}~fa8Igz`$fmjIQ!u46BQtbdt~AkK zKBc8Hv_}tr>{>E8vrbD+o+=f2o}+|{^9_I6CCTWKZNm*}f5mi*OHqr{21{xLvU656 zl1HQ8Z&p^g<%f+7tGwy!cTWP+!ju$q_LII?uGT80><6t6O=el`BEdYLPio(y{UY#e z&E40wt7hO`+$FeZ>SWAx^gz#-2c=3fK?m9H<}oc0S|<~`NCimV)U^=NI~e{~Uy7Cl zCNI1Uu<&j!)C!UCQD%fGA$C_oNk@D?$pDc8D%I^N^;LbiNGkRlSZXzUgp^~e5v&t^ z300Z^*qrkV(r*~SMj&SX@ec;&$SN2cQ*!k;<5P&(`jdWX@#*FNojc@;+_f5Nh6J_B zL$1okOhp%swo zEYfXPA!e|Fjz!(xNA5lI$Ta%y{3TOBneer4OQU?hvkRw9;(mH=8`%Qpfpc^yI0L*4 z2+=vF0+FpNS!=R}WN435Dc6Fw0)hO%uf5({ZG78AbEJLetAa`U()m%k$3MyT)&@wN zPO0!v5_{27iEJD+Tg#m?`mW4WS?rC+T6pro#sW?TUt!bA(Rr4m%$@c8PdVXl#qD#u zd>mwtB$v0SCoMqNo2INlH(^0|mXC7@UJU71WN)Rsqw}%)uyAl>$dWT7UEe=5!8K2( zJg%dhTTokBAXe~<-{VKvwR{G*wZqYGH$nAF%l_*U>OZPIuGJSH4uJq_G>yW)|0pwy zi9u!!!7da-?kx$159$Cxvbn~`{ZwrRblCd z@)%Jjf7*5n`r4$YuF`d!6A_^{><+fHV8+()3Os-UCP8Q?CgQnQmrO0>-vpjg=GcIl z(inTMHK|CvjyA3HIFceGKQjC=l)U*NSzjE8ZY~Abnb6NUs%@~}nc3d~$_03bd5)d0 zip97=6)W%fj3o6zWl+aozniafMR$v_AWft2>Nj z)(0+ujjk8eQ)NvN9zn=1uwqKVy!_GtOwkJthw)TJsl`RYJ=m74I<#&>GC)klA4VD9 zR2<7S4nVOhYFsa&bVZa=>D;OoiTkddz4xtfVih!1=Z(LbawCH&wvn+Fh|@C!$n5*B z5tjRl8z=Qxr!#G)o*k0Aa-GhjHLbhzXN9T?90G(8yd54nI+>X)n;l{r#MBcw#Yp{? zSVr}op%Y}qnOF@vTaDJRl!aR7CepG5`W^lXBn(|EO|2O z)sOU`t#HH~FWPcW>~D`G)Gq0KX@P3m>OxyB&8MrwOrS>kD1ntA1E(1}~>;n2MN zNd_asv{(4P{@1mgrn$y43iFW{b4LP=yJ&Qo8OKMCp%_E918I^fWLBBU!W-R^)Oa~A ziP}Y>-Fx79{@3Mf$n)|asUp9KMB;>Yyj3gW zH0*S)_fA_0+Urs-wX2Q&C-u6CWU8L3syiwxAj-X#T-&ECYTO?o!lZr(xq<^;OFyVR zfC-;qKkBOzm1kt^uw&Hhm346m(1(A{hqZRbxHXhrcm1ecr8@w#!>6g? z;H~uFIbDY;*|p-z6#A&QqD<{0r z&8V$tF^{?pN_$#&dzvYSFQOyEQGQElZl~@ndu>jdzxJb8U=+ctzEqO*9-Un#oX%f< zQ#|3V$w&`(=yAI`WQpga=@s2ip~!MBIh*-Fx6h!pMEK!zC&4D=QvqTyQ4Ua)!WE2@ zbtP`IuCVtrL9s&LM`YLE@jG*p6e^C+R@?7<&Dr)utGG<#>tsbaEWKbw@f-{QM`r_1tX=xueY3)ZV}#n^ST7Tl`&B<%F??!BR`x@xC;c;;uzOM}D~>&URc zqKUKbBf#qHI(nxZ75$LCGq@^$(tSnl_lSie!c66qth~ob9;$q!dbB{po^Zlu856E;2*99xa>0w|BU zGsE>t()^+8l}Ba974OtLBRhGU_n9wXZn;W_yZoSdzOP(X)hQlAqWZ2tJA0z6j;BPN zgYiN?tR^FUzn3_eq^6Z9evKN)@H4L})CSN`m(P-K=gq`Pqt@&QP?D9JyZkThaCsn? z@aV3ChpWF6{YF-xk=S|bsL@Q`$UN>gj>FdfEROHz1`YDyNI{>MuSs~9PuN4_VsyTI zxTQ5rbBM)EQp^5&`SGy~+XdBrLv62;Uh8Xs>zwV*tRri7fiTgr65|%&CxSzW_9S%B z@gNYO8wHeD;v;}q=Q=^TLHy(dj?etx#aR?#1MpJEzScvdi0)nuz@b-S0_z%>+`wJ|>9a~Ngm zSJZ2(KnoR4gKExE%UlDX<;-B0j$6&mNDW+0UrdT-$Wo zlJKsqd6JZ%fvP6@iS}I3&6C-Bs3v~zC)sCvpmHMFWHhE;72`?0Z+_+Jc6d;INmGJb zALBRgx%#p>X1MckBhMqBW3iN+4#h?{!QDb+NSP?A4RX#=maaoS*MqwHDfO{pC$A!b zrD(P-VlIpOX6Wek_-v<*ZFYzfJY z`8@BQNmcA@!X0wc^?xL7M4_;Y;RjkYcdP~v;$o!7Pz;E{`UsVNgXzA`2XCfTLvCOw z<*)KHi@9Y`v1}yyDpq8d8+32SalArEclc|W9Ku>YK@ZEewtYqU1HwBh{?P!o(Jz1~ z`0pm6{MS?L_!W6X{k<9Umv#LSSO074|E;b4e|(^47UE@K5!vn=mL-juaYu%hCkU#8 zY#?6?Ns=~MQz@-~wSm2U{mT{@=dUWAEwtUeB)#I^+(wX{i+Yq4jX(X71iVi`N{69#7NBHv4Q z$W8AG1=JZrWs73_Ok3dx7eV=uP1OK|$#FW1{cx02t?3T1G~9-b(h5r!$?n$_0Tsi@ z@7Uo+?i%BI+0W)REfwivT2)EZ(q5Xwh0=akD@4USYAVv1;;(dnp`rqX71Op9F{5Y; z#jBJ#EWABCba>=Jj+r>yi%SG(<^%PhO6}G!To30z+&~Hx(F*mHRbff0gO+$`_j@Hg zYLR4DIGRGVeA|h`8s7fy#(c~7Fg_P~=a>&Noj@YV5`dkCrN#=fc8=NT@e28~n#N(R z-HMv>dH{YSic!zP0bZb2Wp@ZNT2A`Zqw=MU%jcR3;-LGLNyR;f@2jUmV#zy?ehoU1 zzl;ExmQYu-|0OE^!9PFdxclS6$@?(SbTWyAA`JZfyrh0*2>rGRw`)FGfp4t=Cqrib zDet#U&=?Nx3pqXlNCV`%nM#Ve%Z6w;5{y2a+o>_jjw$$^CJApEf2H zvgi7fOcXM7vPw2~Nw{dEblODSd5TX*DYS&RDv{G1^RMAG`}ejE6WY=qw%#r|pB%=6 z+sho23Z%wgOgr<}b_(OG{YKxyo{U^*#kO+u$IB#2P2H;#KAEG_h*cIo0=JPaJrKAV zDR7tTwJWz3Zo0u2gtf4ldru>33M9d0BL_3oafs~J>p`$;;y3Qx-&^w zAEi7=$6VrXIFW|L^{jxHfH>ZHf>)bw!~etHdxtgEHEZKR5Ks^-^cJKDQUyVf7EtLT z9h52}(m{GBh$7OPh|;C^NbiK+dnfeXA@l%A{B57=^PcxP?^n)uu5*6Z`NQjyWM}QY z*P59%Gi&C)gI|$uNq@Aj-@zeb4t8d7gt3kYo@2D;lvvf-Cyt>P2o#|G8v8~HIaQ(Zgdr%6N~dN!UUz4`Ip|r0nJm{h$S{wfJ2L>(h?a4wwA)v(S55tE6>|u z6#OLa3=W15XxZOuJH|tYWB_^FD_B=g7o3K7p~JG5LYZpam2IB3?N(#t2b`IJ4Tuor zO}>54d>J7HK2eoj;%rVS43$?CAN1@dIBVVUF5Sje_93>32|EMoZ5Ivj1-HDMb?GPE z|4#N^CuaX=$>rZY!vBf*<5LE4i)~)4R6UTK0#GNWz+>e5Y}*%fcnK!-d2bP|^{vtd zp3AJtmsOTWP9q-6r9(&I(AGL(6tEMXGT>BRfqT^s-=FICh+b2!^_T#{2ru##&ln0d zps^^MbplIp5vkr>Cc=;n@m&e&Y0VkvyWw+zouZ*#Y?ZC-q8Ir&E3~5yrT!~Uah>ot z<*lS38XQqye)G;Ja**1xN1KyThA;miM#-=E6svht@Ho2n2|kQXCjGWoz%zHKwnPX3 zRYV%ywN^1iRELsJ%VkPNE zsmhDX`g=8<3!VnfSxbnxp0rRHkRp?sfF5bnW^cAVeQY)vBF|aKZXID=7k#-)MDfL# zp_!%6pfr_MEDzm%kde+ZMO@emW0pa$zLIszIcuTgFx0@_g%QVD|Eec`Mlhf}VOS7y zmG!iuqAYS(d6>s>z{G4oOo^uNH*TOfoFCjk0GY4V7z|5`zBh)YnLuQe@98W)DIbEC zly_ObEdOM0*d?$|#H_f~K>S(SapqiR8823A8)IoZ5V8(G0=B?gVHxZ&zeC$F2(70j ztO@DgcLEc7rp!I}F7c1QHfA)HgjQZrzCdolVJ{=xRQc!0Nui0y2UQuvzp2tdkf zKCkq!4MI|)&wyxaNTe*?qkx-dmF)L8*m3Heo_PUPHRjhsxLG;H0vKPtWOz#ZK`E^= zaTfUnfOSez2K4-jSpnAGT?b z?Qt=W(wcZh$iqcc(V7LUx+ZrBV?m8EK^yC;W7*V>4<;4v$ZAFd8VMuPO>|71RIW`* zTA@-lQM{&J2e$_t30Lccwqu#3%+0iIeVM-IYq%TD#oX@7TboAWN$-!eD*{r?ZH7Tj z)I?P4iK($m>B!L3g}!&#tA&I2Flker`avM(K!;n$#%p)(ZVuL^7Abmga$2%RD@-;= z;D+;GdvJEHZDSM|R{UDG>^lg5%Z>V$p^%PXV&`p`5PL3WR1|W#VPzxHX#Fw;S{e6r zEPd?K+)24cWqf-jtA=M&Ios)&`Ei`>FY5#gX;Cmb{^=g2|Z0x@Tez+5cS7|A%7}P%fN5 z77)r2L5HA$w$Hb`Gbb7-zZ_SF!JbUnG3H^`2<1yOw?;b`GrKQA(!D=yTH3m0^jwV~ z!m0E&8gYXK*4)H1MAnKubL_s5M&v8kwkwv3;ao3L=y;I21=sKtA~({@Q4K_>Vdw#0 zQoZ5CL;}AiE=#ik6v4|r5)z&+&Oe%SWGGN?csyj`DZf%d!=E1Ttr`=?V5nAKG21o#E1HLmmWx@ z@0qq#C9EXbx!JRY$yX}onoW?&M9C)Pk>PB(M;Rup##_cLtNV|xzB*%>M3av4OI+-B z2-Kt?p;XLu)&=@a4Fk^JNV@_SJ@7c`TFI9X1Z!fZNr@5_gc*NrJ@K_i=xm7l>L0R` zNJ_1EO+hfLb1$;W^vPWUZBi`_PMN`=;zx)7RF2389sbir18?M~+6;BC-^7yRQ>ue4 zkOiN~JS)fET$iLVPA3OdmbaY^|FB`af4rg3rMb`*N?+BF;a8zFdtGrZr4^9~_x1 z>#BLlzk||Udkg3F)hu_(Hp}8DCLh$9#Mm{NteEJh){*L*#Vq*0W8EXkp6_vQm5wOs zs)#gepx!soWNkZ7bJ%h~RECkEUU(5SfUoitB;LY~)ljNzy;hD{xlQX&b)PNpJecAh zUnXH@!EB&m#Hob!$6lwLUd3r`pjr*b_Ta83E^G$1*up?vJw|V{!@X5{<2FY!c;=#B z7S(#-nRlHeCLy0K#&B5hww$hqs3FkL?s*_=McN<_D?qP7R{`&C_CZbe42NJPa}mJP zhEayTH@!Vyn|5NmFYo=nAPO9pjc6Nh&)mNcGlX#C11(TlHt#6=ML>I;)Q&G zrPcjzImvra=)#HI8`gT~SbdEVp{>f&2onZ2_51pzZLXK;DL0=Dl-R z`#wJ%f2u*LKz^EGPo>_OL?Aot>Y2|kwIBdV1q>Hedww5py*x-$L9I}uBS*E{`7k6zHaeuf|vPjf3GNf750f#tU*fnzGz(BZhMmOPJt%N=Z| z1SfJd+6+!A!3Z_kbg5E0j({1?msL+EvmDB^*5~Jvdg?GD*Via_2k}T8KN2@dg-JD15SonBP)C4c5A}`e0qwL7k zumed{V$Gx<4oOlW`x{4xBc4OZG3=AOi=-Hbe#l|;dbx|Uf|i!-01!Zw{y~${1sH~3 zXi~(<-b)?p8verImAX|1KWKsMMyL-+UiJDkhIP%v?6aS9!+s&_(l}JX*ZWikM_eUk zg^YBdnMXKQC%B=jfzVl|l%M=N(A(dKkv~@ab>Lhw6$0FaTAFL+s_)6`PhU2M)dRA* z-*?^B^zoidki%EQw{(}e^(6A%UxwdXBpK6vy8_|HrFgF%q;e6e^Jk07l z$R!7?Db6|AplvZa&A?;g_vA!dS;jt=)E@}JNzF!MSwHhjy-L(6@u6g9S^j{V=*6kq z{ub*7!|ZcBza)&yGNx)fuXs9ty?v8N2>IPPbH2>^V z6+G}iUjrP13F}{HGVIU$DNBR?*O%r$WMpz|$M14+kc$?NX@XxBd${06Y-^s+bzz$P ziSe}px_dJBfz$>pEr&M9l_%xS6k`N!VL|-8TN=C8iNW)&bH=*SU9QzIUBR=YOQ^9q zUsRl7^@u>%hb_N@`mLuozWFS?Aamm0zcv(qpikKlM8$<>bIFV*;X0zNkTRieyn`#a ziX$!}-;y;pU_-vA_%y3us&}PodaYv)r{cPDGH#TiOkq*3zlE~2@xqMe zllS-d-&x;wFhrWtE^bpF4dk{N1@PqUkbQhoXBbHaBFGeTU#TFdz5}f_B%?u2~HINmrgk2*u zmv3xF;_Y*L>juXZd2WlGN3xx-sNAa5{YuSY^=&Aqi7lzG0N+ybtD-lbx2ai@?@QEL ze*5#L>8U^$-GqpAXiPP9d@hu}-dIBC2Sl=thE|NgB(b1`j$P1N#02W$W1oOs29}0K z-cC__Xu31}PZI%4*CkRCA>{KVyKy9zG+M&hoG)R1&r60OiR=15oBh0y5C3xd|KBa_ z|LMr2tf=C-O~V_g7n@3Wx?VYVi4?LfJr1v544w-!IBLOmFoTO%-?gPo|5D9*h@Xz< zLP2>IpqvOfy9@*{#|pm?aA%(XLcndwk>4P7SlLG`W~`=3u`}!U9n^g$63Ctx`m3k& z1GhX34x}JMDJAd*l$*lvP`+JFSiv#J&B?>M>PS}oyHAQAysEy$N5s;5Zd4wYFnDj_ zvdq!(mDhEGDAPIK51+It4DR+@l^T}lc37@V>9%kUw6HUNSaN#x@ZdV(np<{crK+=- zr5+~PQTc**p8*vr1`4&zwMb+v8Ol2x_Q*;JQW@oafx~n+l3DrySD-Im=EIh3SK#Rn z5~?sPlc#(+Qnt|=u)Edp5y4#wp7Q)PWo!EG@U?wD088+BQQo!62nG6d1l8GoD?pRi zSI>LNObFpuyDy!K0#KMHx$i!zDwpRHSUW^5X+;VrIleNV(K2Tx%#-PN2#()Ont;yp zuiK5gx_3f}rY1Maby{k%A-vygSp~Szm1WVD;Dmxsq>PU|uzo>xuB{IsW33^3YW5QxY<)Ai|oCBKNuG zxJ<(*S!WQzbuuT8JK8X((`w8*tRl1S$HDoDDE!L-#7|6WPk8~{{P0|S21w9q4sm<( zx-8h<)hX6BJJNr^4e&;M3w@?T5q2l&V3jPybBM;Kb%h{o0Ly`Xh02{Hz3#f_Y3VXw z`*1$fH(&6>LeYD?(&3}$wg~fG<_NmllH8X$Ofo88r`}eZgAIGmxjhB3O+x~;BAZVK zkFM}6V3(bO#1+g+&6h{ygnGnB6%~&obM)@iv-@4x(vvN~cFYo#=F$tv`6ABc2DcnP z3s7$zo}X?f4-3R;ag!%(gcDMY=7W19K_ie_uDl9rI%W;j2D5z zOmapl5v><;vg$#vK>(zW)jxDashgJ##NUv=<#hv-ZUQ8fpbxPCwbL_bpCQm`>}QaY zmI6>%#h{Ncq$q$Nbj!Pbw9m1*Z-x;f)SCb2}CtcRRNH%0XeS1h4{)9YW@{vvT6662`L!gUM3@0hS%ZUp@uMtbTnF%?%DBc7SU7_qPP7 zd49b@J1hC}Kf9d$Uq9?$C*i-+=(rST`n)RTmgY;R%8Wktq%VYF;f^6}8ii$hSBH++ zbiH);k6qtM-a7git=}zWbw{}$VeC=+7 zkfn!SMh~@kj@@ruws_HI3+pxkiHJ`vZ@7w>f!FH_yPx+-czyxXru!YJqD|kp<4GQdTwHve_Ac zBMr!|B*MS`O8Ev~g{?swVX7K0{^kowGJt01*Q)^Dncs#UR=Egp?ELyi>bXJ})*b7Q z<~Sn50cfLs{R5!4`r|gW(x87mc=m=!bj&yp)Z;sdYqIe0Olt(FA6;zxr4cF_KSZGm zy!j6rPS5@?WnPCKPmX=S^ zhaY@DEn)^xNT3bxSG)6*M#8Ah9{fvF@n2W_{?2lAR1aH)^!E+oLYhnw-200gcL2t7R?c5zduw5N>z($~yN! zw#5uqbAOMtxhft3a1d}8Os#1vX7}M09P6xnHKxcIl4hdLC@m{3C*tz+nR&WY$+kvH z?)p|6<%e`Rh7Q&kW+~eeG}CUA@LnsqQJNQ(hEQtR4d1;a^Qf{iP{2g3`YqYoc;0BW zn>RPCzmiiF0%>47OL87C{Nzp8zg6S4_Y{q{=MBr6cExQH!t!Ce%dvx%AsN;ZN_<9s zJ8IIgQkg-O%~Dfarw&n6%y0UgthE>X8+R#O7Z*qaj#x$|=+PqIMry>}7*e^bx$8xu z3i2LVWeXI?$!R7^c6MG~B&m;d_Dxd4>Hw|1!{EFAnwbkR8{RG2J>VW{q|VcU zLQrX2HI7UMt)aW`DkII#fD`!RO5hN$_ZR3`i7^QJwCh*IS=GP&>X*_G%OtGl@-NuL zsoOxEd0+f5Se799@1UE6kj?m{9**r7@-C3$ci^>1Xl_)Md*->O$4^)Os7d+fcm8*V z|DPZIHqZZu69E^h;t~KK6B_+`04wokcYUim=y}tQ^`n|j zkNw_cfPJOZ&8DkTEOak%$79iZdrEm_vDH(NOmAXd8xMg@{Ne6MRI6~-(nul$i9)Kz zbh(0V*K*2em;S&G(wa-~@rHkS5@$w&v{%|_ptwP~?W394TXv;qr04tz53%Hn7?^}) zbxeET$(_o!vMua=SdV#)dO$~Mi83doRhMmF82rTYuy~H3<%&=n1F0ery}+|+vyJdB zJkbZw!=lIRz#j4E7|R3FE5a5}x%3rEEi$I8BI~L$z0?r10q4-5O-io1s895*bRA_= zj?U(sx3)cYmu)iphc&^aeE@Q@{V&MLYM27(>A^3+#c)eVd>2sX`O~)muJRw+@dMH3 z96*^kSp5ya_zxBMrDE?t?N_CWs(@MW>ccodm&|^8Ahlte%=3$VXDmq@vsLck<1Ab= z$CRv~%DwL(hJW*}KdKMw{#18a#46zY-~R=8I_pPC>rblc^~VJH2!|LpmHQs06^8W$ zs#p8s54wkXXsdr+XI3n~*}IA;tr-M2 zIla{&aH7Z<+_`%aFg4K!B6@pljbadE!s6Lp(y4oY@>bDKg0QC0YP`pk?u_jz~1d9fB+5lK4N z7JRFJWsmKx6?;8_;74oh zK0uQoNqeY8fMyjTMPo?MmjOzFFqDEL_($(z7Z4wVYzLl#kssF}KbmS|e#8RvxBH<# znrC^jWH_lmb-|8w!UG&1dXS|oS!;yfC_Ia-*xm-((tf@iF8v(ZsGbaL!9eI;XNU%Z z$ak4izcx{N!ci*tm_Hx%A@&sdANQdDbLao<*(Tj%cx$>~O|vQuZx394P3^tUAD_!x z6@JBAAFcbSaF5_vXI9$7(tHKcA$EWNq`l%w=(rd|>RVsSo!P({-cR~B&Y7Ep9v4ry zh_>&&*S^-Ax~wL9@rw_OL-5(yD(77rr;qrv;hjy4=T|Kc>I4^2%g6O;h^Qyt@)mWr z`|z$KFcIq63p-l|EQfhk0lK4QGe56vVACeJYu}B(xgqQ^@!K834TT@R4 z4V`|+1oak?8eVILoa>^FcE0UjSohYHm0N2Z=42wi8n`ZykK_#;Zo1BBYt0P!<1Vq< z%g$^EYp+?LlA1QYYOOyA1rd(p?ibXNHub}v2%jmH>_m^$BxN7YaO~~eDlv)bj19?K z+RfdFE-ja>Hhm}!c#}WthT+eeM|(?5zGaM@xpZ1WljO7ag)ZHLEMjklXJHmAJIZ zg(&v*J0c@=-jzCjn(N*oe@=Y>HbYo00T{s&qfWKP^I?tPU;_1_8c5Crs@T9^I!?WU z@+yb^B=psU-n1Gp#-b``8)AV`(b)Y(HQb zu)XlBN6M5IC)asDa66X!=xvt`8yytPD^}Mgi#JC~k-73LlPLO4O~4+ZI*=t1YvW@p#5Y{K5wpIpP zZN~S??J{e>gQC6cK$I><yhMULq!VKpZ8kq`3s?I!h3egdq`t#H` zdpptQ$f1@VWKez8Ose_ZF8KsX{Ky46RPjj;S|S)_BCu}962hXCC3#PwvkOl9o|Yw0 zC^B%<(sSoKNUHXRZTff66^Q!bQTf-KMTA@CauJeTgajELV=dkwWlEH&Au4We_WfDB z;(QYBChJ@woPSnndCJV(8Q~RQBxeBO*&Ecm|2k{S2PfFG7G~j|*#!2RA>V@n7^2rL zxO34DP;S{4RY!}nU9b12VB>Tf$#OePpYW@`X#RrH-N?gsc0L46K6S=cjbogQnCOH# zyw)ovO7~%n;slRTPJ3OgaAGl9CkG&Jh{XEka+jPq806O;4Uc`3TRW%;%~)V(ju>;M ze&cBp0MQsSOWHi5WE%}m(owh#s+1^sc{ZpjNffmyqnyu5_8;*9PA3ZXAn94TuLp%@ zZSjkNT^7z!u;z85{$bJ1YySEuRagEm_QERZ|+eE1#-=b;2ckS8NY`Q-a< zvlr*=P#+d7*}5a2Ov-bAj8YQSpI952{<3BAWrvdhn%fsMB#VMJ(ee6t5~RD{P@wpv zz_9cDN;77<7T=wH3vxq$26z|p!$Y&icybYQ_WZ~J=I(q0r&}8uQT86?xi6N^2BJ3Q zr7d3aDCbj4lzddV@Y^S#fA~OF0Khy`p?(88lqk6qafj|&k`5ZNr$IVz*%tu03Nbwo zQ8Aw(LS}w=F)A2vM4LM`RrQ zhaB<(k)W)vpO-)E>R|Dz_e>i|-)POy*9{8xD7GL%qq8@|IHV;~O)_Wo(#mg}vUV4A z2Us~j2%KnFaWBk-xWr;El6$x%y}A=&S8**-#$%Aa32*5YoKFBwvu;=%FL7nB&ws~B z`9@}t1h_BXVl-o8Rn=Nq>xTKJxqIj1j9Z^9JJg;TtE5OIf2gOA*_zz*?NS6^`#LP> zWxJqNa<-g5-DM6$$t^UyPs-f9`|vuzQRZ~>iy{Yi1u zt7K_%sa%Bkb%yH3i62MNjyQx-xJvDn&3U4mOT!W^C zT@b3c>Fm|Jh?yQTtx@}oSnpo$=w>z6y{fow;^3F<)Tj728ljeDBc23%7L%GawlpaC z0!igpiy-c$!H2Bx>@E1b0`e74ABeJ)1`NHpt>#yJP^J^Iy?Tb2O=?#g#2O-@?HDl5 z`1MLgr#1_|oBDI~sc;MQGAbr*Q-XCE?JaTJ^~m1*Bq%O~zn5E09m;YR zT_exSB5zG>xk7n4879lP-@oBrSDI{T$l#Qqa6G#}5wZxmvVO0Sd#SMHV#3(5mF;tG zT*AjLcGHTSxi??*(%zS5RM?pvJ;uV*?wi3d)(%GmznBkgkSI?74W;a>|4)p_l@7?O zxTHDTB}*WPe3^7A)OYDSsM_V1a?vaxFV$8uyCbwO2!xyePKp2k1^d~*`0;Ptg(e8e}H}uGCymfxG?f}NPcQL;N%K^XJ7-`VeQ5bP)rFd?(q4kc`9j+luY8oyva5cv zx*4oBUO4m_U)M}doG=91=p)8mCx-0`%UnY!Pd?WLlXT&oSrKJUrD;X#WXtK0KlL%> zmM41S!_f^c;oa)9UQmQnN#)4IPGd^$sm~D6!bKDV3Giy zwZ1&a$u_hxZ0nr#^vEBJ0jMi0050jpMdhvZJx;kWslDYXk&$5j{ARlz6IWsfc1C&H zG>f%y7L%vfFA?}k>xC`Cx5^28fe2l1a;AaQ58G}9DP|tpNi99UssH{OO*800%~eQ( zNBOaL5|DxX29#X`r(TyK#aocoQSkXOd|n<`tQKkke?t^f$6{1Y^&RxEdK;jy&Fyvy z`;b&v0G|(mG{k=MwWgH+vRYEAtGM>*k_lJuK#4^`dQhRT6+i#cY%U6 zKaKZ|P1`PzwL-@*>@(QccBS305O4GM!n+2ceUA>e9~_evY<=lxEWzvr1sb+ zGwS`!(-`i^=Ew<_u^TCWqjCt zsS6TWWCw;?P}6lFLAptbIX6V6{^dbHo*l_(Sxks0pKYqn+9gY4us`h8aNfPAGdAy! z7w)~+4O!vu<80ju?tL0=H~xZ@#P#6#HZr8Q&}F__T%ytNsx)gYwugTy@A!bv?I!yG z`O}2Y#WHVHq9X4as{Z|L8J>GC&w+ysi+CF+Y4e5V0iXi%+N~h2g_+g^$9$T1N;`YS zcOK!W-0-7gzfe7k0;V2($PY$er~;1CG&jH#XHfJRFk#+fXm)Jh5ReT1b)6&`3;`cV z6UmHy{}5;z(l$g}grO{8|22OM$l34m0CIz(1-0wL&ZtSTIQr1N9LRi59Uip59g4iX z33LQ&XL-H-NqqkD{8#yCQVO5 zfax;)J7|vlN5eEs<>w{Rm>=4b7<0e|k)n$M%mvFeuPof&|CKk8Xu^6K0j=(qKvBz2 z@|;Y{`yKQ?2Xzfl%9{Yf2q(}AFZqvxcpUnhCG-)4V`*~dWHH44-$9@P zIBEop95K8AS$hdVU3B^mYRw&n6a$snzgbIFOcF3}f0(uZ{UwwAt6lu>Gr&(8rs1#r z?OcECj0@5Llv9kI!xcaWuz!$T|Kl7KNvCFwjGP$wP_)1wJE5HgaAW_y?F^cmh8~ln zJhC$K=W>a}nN|d1S?^5De!TRWFxoRyD~yC{ht{p5AZZ@p0tJts%&Qr&H6<0T;i~X` z=_&Oa=eddZC@z-&fy^aBpLco*$uGwSp?_!Dr0Y-D>-fDpLgp2fFO(c_&u>y2B@*Ep zIX@3obZhB;Oxd++RWFCrKE+uIDK)Hr-(h>5uTO7c8n7jQFa9ZWo-O~rRY?j^G%R2B^O9Y-f)3nA8wmv>g<&Cl6bSTHjLfhdH1%#qZbi7psfd# zjCS>~te*v4I~3cmrDcaE+Y64EYz{8F;(JXBEOK(;-Mv1wxVaxZO|+;eIaImZya%_U zUMQ#e))6%`W@lLKct<0gI+f(H$#9YBGUG_D@*BvNEl*3QJ({6LXFk{1L&cR@4pPD3 zwd>lrqMA!8ob77K;cXr5F*M(s+~C%doLjia$WH9$QMG%NM|9>7V0O{vPcjnfG<9nC=d zAj7JdI5(ib7nvSQh$Iv5Rg;hru~}$<10HPkk&M7$8Av~(0L*x`neX+|F%m^k&x+m=SZ5`2z7`y z!_CmQS(^8eQE#6+JX`r}=a|Pr)65)}ZpWgjC-dcEiv+uFTXpTsG%A@;QOEd@c3e=?u zGW&8;#ui^w+av)pA&3viTL5PRDPRr=YjfF?0w6U z)b<pQr2_KQ$?;F`#a&_C4D!KW6@L)DAD4Ofy-Br$!b0xscehOzO zRC=YMw)L9q<&bgg?T=!Qsc1U)E{=^K1_iuXwIQfXCNMuMGVJ5Rr4H*~3NzmAu^fwC z=lc$Nu|c6GcTd_rQN29ZN6z@@K8ADf4KeQRcJUU_Lp%P-#vvhTaDvKUsoarVtXyY; zKec+e2UMYR&oRwBW#kFXa-%oi9QJ*2iK#xD_NQK>WoZYh2m(pMdglFxWRjg6gJ~i; z;)*T?GLMmH6QhreVK$bbdx}H>TP3qKte)SFRPKhgfm8^TGN);)O+I3F{K){nqHVbk zQ;e0Vgk4eKdRaBFLu;v9F_E+*B!zNBbEdz=LU^FtN&5mg45{u`scOlT4)x-9I7Vt3 z7sx&n6HvF<(Hue$h+%gdA{M*rO;bn+kMg`O16A!oo=GQ>C4YR1&dL|XH`eB{a`uL1=MRXYrGIFbyJgwLrQ#Rf+u{5*LN zD_DiEUqmbp#P~uK##q?7+)2!Ed91bAZ9nxC9@xbL>s;-~JWOCrOcekNe4Oo}Mg&CHy`$j_K|cT5}UNT8*UEn!1jc z#pk>q+e_RhkoI#^@)q@L z(v>@AxK%kP+PBSdpI`_q3dhpzu(yrvxIcY{-}!PPe5AQbuptQsv~pD2ZdNzH*^71- z5^0>qOh`NAWhV>j1&m_O^U-M-qCqz%afwLrlIwaLmCjTty<@u zEg=eF+|yxXXK`~;rVMofr(w{!?o)ro2G_xRuT<a4M}tN*N&zt4NBcMv6T+jA9YxrELj-v>6+!3V+Gy-8$S zHHuEi+2+Cx@7r}XZ?|sLgqLUq(8W=@61>D|Tp|fcazFkK3Stp@x7`{4HhUck01~^I zwve8(Nw9;DNPwt*;FXWWA~Fme=+29A(}k|3=by63MWlsqYvM(E;ON=<35G~ONX@jY z*$)_6$H3DotgXtmI(v2b6#n!2vKnza4L9zIzXmil-Tbmrhiqkt!d@_|=$7uFAWBd- zzF}8F7R0$PXXU z)Fn9CTR;CS@V4CeP<%6!^1Vt-WsY#smP0Oh#+>CCtv#nxT^ZVoQ2gS(L5xv0LXFD$ zqaPYCu(JXjhVOU=%0@|qZZigl&iN8jK z6+T~(<00cOiq9taN&t}XK}vmhQ8yPxdW94-LdAFH3pVGEmL#Z0fS8leu)>c!o$^!t z;eNs0T5ZgP<~MOdm?$R8HXnw?cP+5gno6<0!_W*aZ5mc@9$1PiYph@JN*7q(b2`$w z>l3R?|5R7r!+4=9H(>6;I{7d~2yQerVnNv0li`aNKsIiP94$&@Mjn5GwNVE+(V7+9 zyOB_5fj^mu>gDX@0kT4!&@%wT@$6Fm>^t`~LuA3BuuVMYi(|$uo_V{8WG=L{idw;+fHQa%;dA%a$aT&_>vGO;>RKT2dwCef9(#L- zrFP5+ujGdFPEZq%_$fqBJ9TnH%R!2)&OVG!iVn~!zn3jJE!?L?RL86Fp{T=rq5wRt zeFf#qX)85FBP^w%v(2J%(|o43Pl2srj+x*fnekvw$US4u^-ko-S5nh`Rcu*M9KSkVHA%$(y6Y_?@$|4Z644;b=n3L z%wmhj+v^?+-L55&B&GG=hXf>(pq?c7gvkv2|OYmnEgi>`gTO0Fa#0h4o(eE+t8qw*nG7vbJxhYF7AqOqmc$gi#uJYKONXYNkT|b(_Dt-;}4%~NNLyLagr%6n|fUGL5rNnOPvBpqZggm5}e5?ko__^4Z7bvPob z5AT|f@>uMewx)c|J=>0TFl2RIpRSN=phS7#J!i)bQNwWvVcBTp>kHpOLqeyY7yCUM zKhtNteNNjnFsX3=GlgyT61KEk(Kg$x&}3M=hMu4Bb!z{isO$>ofR*w7Hq(PU&Oido zoHu`TV^r=#uPj(qj>Msvvd-3@_=EkBPmOybfPmJox_WxOCo!s>kB0zomWPFv&`N(k`aB^v!A3%hl`p^YV~0qE6Me* z)|YAC4lfuxb-9f@Oyd1c)0W7vgBycMs3+VzbptJVO)WXjg)Qs1xFzP{M=wzCzPU}5 zLcm;(m%TX4yqAGL^UixHe?vR77>{7>E=Eanq@=4$aoskL($RjdDv>Pl3!WqMtS_fx z<7+YJD|YNnQ+)Q~LJna~!f4JcVWYS0;^sI#Ya&SqD-+Ys645#}du>}hZ#+%g%d)Gw z)6*4w2osyyVb9dV3za*fxDp`M*2o!{}7 z?DgUv?l|wcGR!-##VPzg>dm8qKzhwvNOVkf`NfAFn_*D*wTuAMkQDD=J_BXvJ_{Si z;AkP6dn9dcKtMao#es%LXinarnt%r*eIDCf_waDntB4BQLL_(F!bZr)v~ zP6Z%1*6Vh#woM2)zvv^bbm}w1ZW?1?pK49Wm^eu1LEaiTD<96vLIjvLB-LL(@q23O z_rl?AqJQX7^}?5T$D_`8^}n3d>ssu)|szLYw7TvNRayxA$~&p`V$B z&$LstZ!b(*je8aGePO%_-;Jt1yN2q=(^);!s>~PW=Q51bWabic$AUX^<|>%}eSiI-@Rrov z$X9I4!iu=oAR~kVsCYLaCks3dRJ<%#^rmc)o#6$$z1O{%G)-TfgpJKBg^)~2N|ignKP8F z80u2VVe`Vz99JsCjdt|fp>x2wF0;NA$Tu_GmB~kVmsF3)&52VFnf4?Vv-cj|xsryA z_co~=StQ1!XhAf43Dzz;#5UcF&Q=&$a*Gf!-?kN!lffb)0-r_(b6p^_TB)yJ2n?=!7_AM{mp{s)C!4Gb7PS+?~5aM zW$6T)KL<^}gh)W9mw;em($!-4$_4gxy6&{{kt%Fyr;>S=*&YS6S039=QFw!RoUkxG zzK9Dz`^k?RD^R8>Q*yu6ec%=ZH_0E`LFQhi!9;%`$EjMfS*n4BCJy#2a7Uz#DQhVStP9eOdV5o|Ni z$kXgHU$y}+$ry~gHdVBp_}6-TWXWOG&a(xGSoS2e$(078nlhb4Sx+|Vw!IIg#4P8H z7L-6w8&^1UwdM1d9^1&jV9W*~-RRy9+s)KODGz(f&+lHvk+hs(Unh}DqOO60l=g-Fz;**93^Md+MN<(;P?nzya` zWbZaU6MH1Vib^weU3od;`D|{R|8CuV-ir<3tv2GYq&{maPibU2wv;@h@GE~?&U%5t z_4<#`>vNgkbZDtbwK4mOXw%QHtLyAx-#8Gtg-@=ZxR|-4i`-N**IH|jb82Pf8)Q>3 z&xCdOnq_i7^}rf9z1jK_Nk;@jm|F-Q?%{QaH41*Y^%R}IS54-0I}#_Puz#Ph?|wn7 zGYzbjop~enUcBTjkm(A)bqojNPp7>EPX)3uhL$lUF@!NuGT|j+_?bK^5@|aypVEe!^x+t@3 z+st)%&G5G8!>{d(weQHdRN8|>LOPgkt7*(#m1;LiTmpac7PNF3^km&@4at?Ia|u^Y z&;1Z&otD(312{AHP^<4pOr9tQ8Ym*~yJ z5N}rz`?Z8RorLjtp`u(Gj_U2iRx z84&LL*5W4EVX5wvYJ(VRzYwMo4jdiq#tW^>kxVu@zdgSooKDwEBs6jg$+wTvoiUqu zra}A2%26~z8UBD^|4cjesSH!GAE=egyJo=4rd+G&!Q8#M*QEI%huHKz2C9$Qr=6#U z0dr7=L8W{5OIU^`Tu6CA&?Hp@FWL@9e`%|jP!(PA#o%S-I#+OlJA$WK1KbEgXW@1= z8mv1s^O%@3zqo2c#SZmZ&F*{PWv5RNz$4w8WNMROlP)QFNWgYVGd{KjbVw+Dy4wW$ z|El}$x2Cpj?H~#Y0#c&%AXP*}x}p#iA|L_+0#YLuAXI76i3-w@CZK>Ky%XtGBE2bK zC;_DRBE5$s-l^_=?mqXN?+^HX;CZqpStVnRcZ_$xt}qm5$*f!r3910=Y38cGJ|P!f9awMe7z6-NbGZ|4l_6)9Faj zkz~2OdKFgSOrR`G%O@2}R-fZLo;5;j^5vx2J`b7LHg2EnYc9jRjESg8k|=6<;?X9L z@WT6{XAFAL%Rv}syl5EvyH^=Z(aO(F&b6O!qWru)L58lp|L?Cmpt{?CtaKmS_-MJ| z)1)fV!g@)eCT}dSk*Hcj=Fx=LI8XrnTuhM^(d^}LOjvwEjgTjOb-1QoYaw{&?rzpM zRZFNdDs9p2iJ{4o%zzG3RhdzpSB1aJ(_iO0V8>4}#>NXV*32mF@n-p*;yexe=#)5V zhibD+>e=$al+u$}E=!!WsHOV4&wRk@Jo^iT=v#vI_Sj+E_ZuWpH&(P}fPXF9^p9 zcV~b^`c)QmbL?AhDfQNhXVirr130-RnvI$J>hBaZ1pUeIc3ML0Wi)A9Q!D6{FAbDlBVGH;R1~>zdb`v54bg>R9^NHZ|FD)arxq z6V~$nD-P!TKGdRhp;RgKF$!s%Zg`q*XpL&9R0!51TEguTR~x5(sll*b!HC?M@8)N| zvPFr0$riF|J=Wwga@URLL7mR}`@|_z=BW|9Ok8{gwO&8(*}~GKrfQnSr6^TbHkNBT zEz2M4E4iAVht7#9KsN&$!v#gS)K!zUdR!w;em6wPU5xb> z{V`L9+HtpZ@*a=h>$xfGu@#nL0J}2JDH`El*c=h452r>V&IH)n@^0L=Xzp8LzMi8b z_1wUL;9(lwWhfh<-=Z!vELyR%MXpH^eY^LyV6=c#YEUlO>g*sF`0C!9YxY@bA{Vby z7eSL<(-F=t7oE<0u)hLVGV@xuZ?O@hv(_o_uhvgS=UdBq`lNs3a0}@|Rj3@sL7F&M zBhNyfHS%y%=l6U*ml~q@NHB(JjFit!(PrX8^pP~$)>b^;!FKCo+cox%5}fFdLhdPe zEqRdG?KuE4`UBi`rUU~t!wKvOA&~h8@i%+yQ_JeG6&2Netoh>Yyvmyuj_gI96@?Vi zIrLeXCdlp#<1r=Cosar)qx|{_(rAEOw{yRcyOrE}WjkEm7*~51K(VTs&?x-}xePX_ zqf>~Ais&)6Titw^qp|n!7oD1~H>_8@)Y)p?H8LF!SS`SO==0W)smPYDjYK#<%#kF$ zLrl=lAEZnThs>sJcHLNE!Bq}z7h>|=?L{un_JPTCcM)l?wWJRG#CDkQGuX$)G!QQvIFmglmPrOEO){a1uT~!Tue~ zfDJEd(ZffAHo7ofh4T_jikqV0)l?ZMvu*QgOQAais4k%TyTsJ-&BRuU>Pxt=VoRtuZBcmu}%AdGJADP&S z3aRg(#fi>EYnTyek3~&|$i7z&Hyz>R8B@IAMe)`9VYa*2RP1~}DVylE3l{5hvH5}- z8K|#LcJ^mIcG9G@Q1iD2F4*1g z70v8Zb~8XR3=!Kpn4(pKc~2+~2EOQEf4-TlVT@epF$4L8aOgG_S!#=}A|cu8L~`B3 zu9d2_FulNjsmdMJZ4WUXe@&QPLOO*$)1YZdiIvNpLk@*L~kPLOrY-Y<5|v0!k}N>;}`Mi=i= zvm&N%Y;o!Ppz*K@XVoW2{#iCbUB>(O+K%g1COGwI8z>}EDsM1%5PW`|u^7-g@4%~^ z*ckrDPpU>9C2cdl81tTXVnNs4bZj(qzqNcQru<5bYMkGU zv)5(enigY`i=6*1A&I#IdMly=dN<)gd#zj@#f9&v?+(lJB)1z2LwlbxMl(qH2Ib7H z&UU|$o215(v!M4n^7;-{$*PNuO=3pX!xvdkFUf6RmM>=yb{3dZn35`axF%f5CT%hdE@Y`u35KbLmvdp3;(U9OBMb8JrRmYaIswoR+A(PV5;PLw^5m zf-G<2i@O^nhwPLQ@upsqsC!w#p1O4C2g-|(xt{zG-H&Ut@D zAtu|JVBlX!ly-F_rAD=T6kbo$%8`DT#2kF|^x9F0;*nd+n=`pBRnBq4^soSL(OoRe z2<2wRSzXa*-tVpMn71VAz%Oos8jgRv>w4yy*tT>^EdRAczil7C>#j&ii%5U4Bc$PH0j@&!CWi*?Pcy@N-`_@OX zI!7dk7-*!=KD5Usmd01PMfr>>F%ipl~H^KZf2((c$mEC z>tZ)DvnINO@#Hf&q}F;)e50IwzN@^LhF1*AnI* z22G({7U)w-`QA$FI2(fX;&Ah8{bAG6;gD8mH%^#^#Lf0tx4UuT=S)MiE~J#``eq0e zL}aY2Nrf7h_3+gOu5`i@cORbjAe%X2I{|{HFE`&F&U}*)=6NkX@?wev8`EINi>F~v zOdoblrBzWvH|l~X7@(*+xpkjt<%?y<9YEB-L2bmf7sV80UeuVZ0)!S^;aPfEX04_P&%Tw{PDNmbD<+nY!K+8r! zqr|Ky;IK>}M~UN+%LLG5V9{w<6U*P7F<$SqTg+;?`N+__>P)Ue1MtC@rLD&edukI) z19i$>adqmcf?=ej>~>~z>{CUyt3^m5@5?yek9EC5AA6*eX@>_F2!iqGU7IVS>4^p* zKcZo@hx>OXpX!x`uvfk({9{}b6fluzL;<_*z#LmzM2SL?jqtyOxz zTH&RabaT_Q6iLVjerwMU2JH{~wx?ruBAPJ=P_St6G4m}5(s#rM5w+KML%hYO99T$E zRJqmCqnKf8`W}hZ!NDcUbA0kw9|}HGAg)K!O^UK`UoR>LdzI?iC||aUUTI<1qxWz7 zQPKvq+P>fCq)BXmZwfD9cV_MWM1xg+O~)-+%4x@F6ud}%&$@cnUC^|h=e$a`v?!D+ zoSSbVf_~T=-p`L@wjTJX?$oM@I~)Bde5Oq8WDw*5ZJRno&-qzeAHGm2e_?CMc_9*c zT`!fL2NR1qzPN2r~jPv9`Jp!eWgN|h-Xjs zWpAz*%j8{5%SKh-l^8mqtEoPE(?vbCFrEL7;+XyPv--Q1bI_~}%6d6WpttbkIGvHz z$0crx^>@2rh}a}&Q?vHRmi}m&!Lv;H4#gVTY;P_;jTYC*RWP7kbTKH>yyc@~iEGry z4YzRJHoIZF>Ww{b&U>Kak$!v^SRlY4HdR}V4ia}u%U(G6ar0M3U5_4{);Q-y#9zuG z(YagXOrS#u$${IQ?}X~ViurGUbvrax!HrGk7e0vgap(#$Tse6`o40)KT-UV}zLM;7 zDLx{*NjPZ@-HGv_9WC~uA)ks{*rIq%ndsY70&(tX7Y-Zz1X~^p9ffF$$K1hGOQFoZ zY|=4L6%5v?)Mhheo(8grO`i?D5M0qL&v3j)`Y|*y;9pl z8V{)z$4oo!P1<(bkw&@3^QsRWi43Lh^5r?G3JsSC=j)x1Sj%*|q?G@-@GZF{QkGGM zW6zxpE^`?ZQ^&rru~^}GJB|z+@RsI&n`T8Y%iJxG{;uYjC$N6`0W*nL;Oejk-sw#` z94^GE<9_u{ygF{h)*I$?Vx64KX(kjlRLzCxy;oWl#S+`RVU=1Lf8GS@Q`NbWS6)v3 zAmtkjyEeH!?JZoGeL0{ys^$8apK+BA^pw}GtTLRWoP*1F!L&`z)E~l2 z7Uf8@g^3rVGORuOX9oanptJ6@;|X&(bxA+?aqOc=zVk^ks%#kJ^s^8MM2^M?a0fQr z8)SZagviypcN@m9e-VFHsClHjbf{&zXvWq^;Rtu&euR1Qhl1*JknFi&q2Sb*)sM|; z2*@K;HL57uzz!>Wo4zicWMdX`?uf9tVM898mWsN^&n$3a`~X@yPM8vT!G&*hydQ8HdB|Vi0;^=X)k4G<69m|tjef567i~|r zG5eI=2);d}^HX03le^=;FXph3Mt(p^u7Z(h3i`rwKsRQFdsxA29j@zw(Wc*gw;WjQ zWg-f!z9~ZCQ|8NOX2z#gh_~e*5EF^kqbwBR0xLv)r!k2pWkdkg>eKS!QrI2wV97J1 zT?!7j`)RQUM@D}_K8cY7Y|PQqgXk*K`GOCaoYnciD1ldgQb zJ_s($VROd?8VlCI&w7dN36Ni>hQ#n0FVCG(u~qt!?zdNGdvZggyid$t@D)!{PBf#8 zuRX=(W(lzx@SwHhgkwsX=++f1$s>#W(x4+~?(t4_oejRE$xxZ0X0BC;HTSe<^U6wl zx$5+7Oa3@{Nix(Ien1aWK1`So@bW3>HjTOh&}>q>Bfs(OD3^sR49Gk;ZqHzksrwY8 zSmdGB*nHTGe%T`wc4H63tmDmpLO%2fqzQl0mQBp|NoynFM@Ewq@vJ%6sry%(52S^N zP1GbuP$)TfRt+IZ`f%k7G6o%fr*{@xbrY*4th|5VYcDh7T9DQ=p#SnGgr^dO1`!x@ z%U{%GVE5m6f-BrDtHxGK!#+n@q2CqGGCn< zglH5$kG|Iw-i<%A_w?IHcCfPF<*T`3r_gN|K`7)wA3>J*Vg)-&&J6XcpgkM_i@U$o z;jS#x5~z(eUTqhmsbG#Pwa)knA-a#C@iJt+V?prJ z&njpir+qlLvfod@{92%n`3b2U?g* zkOwqHli2-TbR(g^vQRxb{UAYFAm&bpP~?F!j}T1O+=Pssq9rjjcm{?X6~A3B6K(2Y z_;_?S#jd8R#W8HE+6%kClSpbI>&=q^*rL@jKOuv>KvoF$d5jRdPV^|pH-jA3PeBTt z?&Q5G`Up~Px#M7DR}F1xvdeQkB_8*Q`Hwh}3goZjo9ARnuJH#U1er|##H`bYeBQ3o zG`;>$HIm3_xn_%NOw~8%OtweFUr_Jlt*d2g9d-6yaJVygP}%m?d_SJ#nnk2NC~$cS z+n5ErJ0|!81Le5jB(l{gt&F7Oun@fVHGDJLC1lo$C_R^4Zx;Hu4Z zz{J|+=A`1e3G+v9QdWT;wwi!IY8zlsuw_>U!oI_dNKZ>on2-Pz2MaC_6EJVDSJxRS@-5}QdIu423d%wtfxKDCZ0sh9-SE=qY+lv5#+3iy+}0K z(kN!GXkx?rQJ=v6SD^;6AC=D$qPyMFA06$%qZ?F=JB;n^VjNnsmKkRHHy&e%??EBT zop$W@bDP!kn-X7?m%KFHywoxlA}XdYHifh=6`>;{|BE zjTlKRq;$rtGqK>y!FcKH;=|W9;3u>Fge(KZEC|*(1S0K0J|%kcU8X2@D9*hNG^@xl zngV10+RMQx?mL5t-D`yHo-6^f7crTe`%+P{VXWoU$$08C>p|6b&8phEielL?-ut;6 zR-^CHBv0qUOM@~JK*BlfL~rtK;Nn?2y$>-HyzhBv8E#?n0?hNf7@6UJifa)YM)O)i4sBCY(c)3`G1Z#UfEwa-9C z&`FZ3l1az$#+tdM2{$s=ScY`je|b@Tfy@#QHy69;%Xk|of837~g1VigjIvaD3`-;Po7Yf%;X-u)mYT9cGUTxE9aS^W978`axv!Oemps|lU&^j%z8*J zqo$gKjaqj3tM9jgMPor}KTr&>pmyBD+*>zW+ef&39qf*-YQ2q**hiA(GeNAF-vP}o zj0#8_1CH>F+R_##T;F=N5m13+EZT~&KlM@nPx#nB3C~W*rkw-%X1Ef$3cy|H1I_F3 zJuO^ZRNW%s4wYH(FE6GLc#zPaU%*Vh{=|o2OFGX$elV>__g{RbU+W-I{&K?^@2tD8M1ufVKNSrBCjR9?*&9a zY9*H~$IhS`(0xPb%Ab&dPflgc-nN}|>wNs^HZSsMD>?A)3Va6YLniLn{ym~6`qxO} z;5U00z7P3%$p^GU=qj=80_`4sy>8;mAJ~z2g3hzqBBTGtD|8WiuIRnQpAf}tm+pNc zunia~po_T#NrmQppfXqBq$gVQCcD6&pOpdKxW1a6L~n8?lPiU`3cYTCAC%|=e<$do?ZhKsjv|g7b*DnLukTK+#Uk^OIW}Ql<0M2{e*}!96tR0Ioe;I?y(he zlh%(6_GVJp`~UqATdY1ZkpE6-Z48ZXMBnm8_^p-Kx43-0@&x^h?cK4 z|4%=?P5a;eHUGtb_d-v-gGu~?Eba@N#&UwgiF>T&K2 z@Un)$aU+Y-=a+4w0!fdtB;R&oj_wk(gs=;*$J+Jz5Z@x|4}HCEF)I4S+T6a0yH zotk)~Av4pI2?xtlvf)H7j|m3G;o;?{(ONRePl91dsW-m(9~)G)oez5`y{qAlU!lnZ z(YRVIDwJ?@`|*_m3&SNin7A2gXEOO6Se{A6nBm|9OEAD!+YF+-`KS-+=OdQu+zh0duI;xxE$X7Juvob zz~DW|NB*R_vw;PrQ20OuL`+XIxk{ECDeBXVqzBpm?epD02?0)3PuERhCeZI_mV7DO>(cOav z^;mpyO=3U37nE>Ph(-wwA`!@2%j28Js|XBpB6AVLR_GRK8|)4a+)_QY06p8?y)F6c zhGKo2iCAv;o5sSaANzT*Rnao{3RXdrl*V zr%gk*>1Yv_K;H(Je;(liz6e!cP1sxuMlac7m-EpCR*d#`N~if1UW!i{W1p1l;RbqL;=`h$;0Z^oIf+cmQK?RLEPBQ{_Ttap?ml#vB24I}6hmf|7a}Ksu*MefIfgVX_q~ky*2D?49 z_r@>cGf^PeCwLLQjVJ%=o34(4fCf+hI{xr$B69c{`b414uIm(IzuB(Qc_J+L*I~cy?Im-TX?-m+uvBZ-!c&UzOHR z6r6bAuE&2j=IXQ9s!=@FbNO6`UT;;tv?El^{ySILr|MnVtTfx~*m~<8B zQk0V#+4Wo0U$z`C{;=y#7?n&mawGD3YLS2lvEgLtUTsCr?tcvwkfqvcxl*sQhCriE zxg5FqnFKEJ>6}u~`#InmW#ooWpZQ}wDcLk~ntjRwnUjj*O6_XV&(Xkx) zY_1Wb`;)%)5_^pd)Jvdm~f#qvS=ceh= zH-A#p#!tyni|>;2#2X{778!El|0S7lvedx(t5-|f{u%e~M~GL!-nne+u(j8N$?Lym zoF0{P<#SXu*%khe6Qpt96ggj$PxM@Tc80N?$LwuXW%sl?^^0wh`}#+tD1Hc_HwueG z+@P<_YX#EfUYiT+Pee#pQE%kRf);l~$(%(ucF}DK^~bKvO8jOv&%RaGo4jD)*_9st zrqkd5R&8jM+jVm7r7!JzLGs`=xW(?1N9FwqH)nQc-y|%+|5qyt<3gC!4C!_3MpvD5 z_xTj7&fD`v-*_j<=Sb+wnWW>Ey4Q0HstEBY=<${A)7G3B1S-Yyw+`nv*0UdpRMw#@ zH1XXbZ!CG@O%YdLzOwl@K+h4)*Gn4Bq}N;0Cgt_j-~8CQT>I8Y*pbJ?Z*%oz)pVuw zqLdEhYz=YbLLVlD3N~zjK7Bvhjg3;^1U5Sr(}d zVwT#MLAg?GSHCHNjjWJ>Tz6UYu=;M8-4MB?eRR)#xi*1U->FtGwPov>M?dj%aD(b zRqVW3Cn*;3353iLw}sPJq9#RoAaJi%*fIwZh5k$IBdiIY3(u1|A`(WXpO1m{r+?^vwUIDI zr`p8IX}eTJRQVFaV`<@>4!bvd}V6A6x$at~*$>8wCw)=N-Pw+pJ?-nfh wc5C`q7yCb*?0*;1q=T^N(7*mQw08Z&kq}`9P}2_~APQm8M*M&GhyFSAKe2V&3;+NC diff --git a/x-pack/docs/en/ml/images/ml-gs-job-forecast.jpg b/x-pack/docs/en/ml/images/ml-gs-job-forecast.jpg deleted file mode 100644 index aa891194e63469bae6888aa64374a5a19acca30a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 268782 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 -* <> -* <> -* <> -* <> -* <> -* <> - - --- - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/ml/overview.asciidoc -include::overview.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/ml/getting-started.asciidoc -include::getting-started.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/ml/configuring.asciidoc -include::configuring.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/ml/stopping-ml.asciidoc -include::stopping-ml.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/ml/api-quickref.asciidoc -include::api-quickref.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/ml/functions.asciidoc -include::functions.asciidoc[] diff --git a/x-pack/docs/en/ml/jobs.asciidoc b/x-pack/docs/en/ml/jobs.asciidoc deleted file mode 100644 index 52baef720bac6..0000000000000 --- a/x-pack/docs/en/ml/jobs.asciidoc +++ /dev/null @@ -1,33 +0,0 @@ -[[ml-jobs]] -=== Machine Learning Jobs -++++ -Jobs -++++ - -Machine learning jobs contain the configuration information and metadata -necessary to perform an analytics task. - -Each job has one or more _detectors_. A detector applies an analytical function -to specific fields in your data. For more information about the types of -analysis you can perform, see <>. - -A job can also contain properties that affect which types of entities or events -are considered anomalous. For example, you can specify whether entities are -analyzed relative to their own previous behavior or relative to other entities -in a population. There are also multiple options for splitting the data into -categories and partitions. Some of these more advanced job configurations -are described in the following section: <>. - -For a description of all the job properties, see -{ref}/ml-job-resource.html[Job Resources]. - -In {kib}, there are wizards that help you create specific types of jobs, such -as _single metric_, _multi-metric_, and _population_ jobs. A single metric job -is just a job with a single detector and limited job properties. To have access -to all of the job properties in {kib}, you must choose the _advanced_ job wizard. -If you want to try creating single and multi-metrics jobs in {kib} with sample -data, see <>. - -You can also optionally assign jobs to one or more _job groups_. You can use -job groups to view the results from multiple jobs more easily and to expedite -administrative tasks by opening or closing multiple jobs at once. diff --git a/x-pack/docs/en/ml/overview.asciidoc b/x-pack/docs/en/ml/overview.asciidoc deleted file mode 100644 index 5c941b4eda24c..0000000000000 --- a/x-pack/docs/en/ml/overview.asciidoc +++ /dev/null @@ -1,21 +0,0 @@ -[[ml-overview]] -== Overview - -include::analyzing.asciidoc[] -include::forecasting.asciidoc[] -include::jobs.asciidoc[] -include::datafeeds.asciidoc[] -include::buckets.asciidoc[] -include::calendars.asciidoc[] - -[[ml-concepts]] -=== Basic Machine Learning Terms -++++ -Basic Terms -++++ - -There are a few concepts that are core to {ml} in {xpack}. Understanding these -concepts from the outset will tremendously help ease the learning process. - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/ml/architecture.asciidoc -include::architecture.asciidoc[] From 6efd5c06acf7028f8bb1976a66b8fbc28ca7adab Mon Sep 17 00:00:00 2001 From: Jason Tedor Date: Mon, 4 Jun 2018 13:35:49 -0400 Subject: [PATCH 16/21] Enable customizing REST tests blacklist (#31074) This commit enables adding additional REST tests to the blacklist for builds that already define tests.rest.blacklist. --- .../test/rest/yaml/ESClientYamlSuiteTestCase.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java index 950bb14eed9af..de4b451807d99 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/rest/yaml/ESClientYamlSuiteTestCase.java @@ -65,6 +65,11 @@ public abstract class ESClientYamlSuiteTestCase extends ESRestTestCase { * e.g. "-Dtests.rest.blacklist=get/10_basic/*" */ public static final String REST_TESTS_BLACKLIST = "tests.rest.blacklist"; + /** + * We use tests.rest.blacklist in build files to blacklist tests; this property enables a user to add additional blacklisted tests on + * top of the tests blacklisted in the build. + */ + public static final String REST_TESTS_BLACKLIST_ADDITIONS = "tests.rest.blacklist_additions"; /** * Property that allows to control whether spec validation is enabled or not (default true). */ @@ -128,6 +133,10 @@ public void initAndResetContext() throws Exception { for (String entry : blacklist) { blacklistPathMatchers.add(new BlacklistedPathPatternMatcher(entry)); } + final String[] blacklistAdditions = resolvePathsProperty(REST_TESTS_BLACKLIST_ADDITIONS, null); + for (final String entry : blacklistAdditions) { + blacklistPathMatchers.add(new BlacklistedPathPatternMatcher(entry)); + } } assert restTestExecutionContext != null; assert adminExecutionContext != null; From 9cef7c67041502a9ec358b5ed74e7af241f8117b Mon Sep 17 00:00:00 2001 From: Zachary Tong Date: Mon, 4 Jun 2018 10:28:36 -0400 Subject: [PATCH 17/21] [Rollup] Specialize validation exception for easier management (#30339) Extends ActionRequestValidationException with a rollup-specific version to make it easier to handle mapping validation issues on the client side. The type will now be `rollup_action_request_validation_exception` instead of `action_request_validation_exception` --- .../rollup/action/PutRollupJobAction.java | 4 +-- ...ollupActionRequestValidationException.java | 11 ++++++++ .../rest-api-spec/test/rollup/put_job.yml | 28 +++++++++++++++++++ 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/RollupActionRequestValidationException.java diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/PutRollupJobAction.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/PutRollupJobAction.java index bb64d97f1c87d..d4b7e33123054 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/PutRollupJobAction.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/PutRollupJobAction.java @@ -88,8 +88,8 @@ public ActionRequestValidationException validate() { return null; } - public ActionRequestValidationException validateMappings(Map> fieldCapsResponse) { - ActionRequestValidationException validationException = new ActionRequestValidationException(); + public RollupActionRequestValidationException validateMappings(Map> fieldCapsResponse) { + RollupActionRequestValidationException validationException = new RollupActionRequestValidationException(); if (fieldCapsResponse.size() == 0) { validationException.addValidationError("Could not find any fields in the index/index-pattern that were configured in job"); return validationException; diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/RollupActionRequestValidationException.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/RollupActionRequestValidationException.java new file mode 100644 index 0000000000000..d81e59a55ead3 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/rollup/action/RollupActionRequestValidationException.java @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +package org.elasticsearch.xpack.core.rollup.action; + +import org.elasticsearch.action.ActionRequestValidationException; + +public class RollupActionRequestValidationException extends ActionRequestValidationException { +} diff --git a/x-pack/plugin/src/test/resources/rest-api-spec/test/rollup/put_job.yml b/x-pack/plugin/src/test/resources/rest-api-spec/test/rollup/put_job.yml index 080fed7a80ec9..568a6261cda9b 100644 --- a/x-pack/plugin/src/test/resources/rest-api-spec/test/rollup/put_job.yml +++ b/x-pack/plugin/src/test/resources/rest-api-spec/test/rollup/put_job.yml @@ -159,5 +159,33 @@ setup: ] } +--- +"Validation failures": + + - do: + catch: /Could not find a \[numeric\] field with name \[field_doesnt_exist\] in any of the indices matching the index pattern/ + headers: + Authorization: "Basic eF9wYWNrX3Jlc3RfdXNlcjp4LXBhY2stdGVzdC1wYXNzd29yZA==" # run as x_pack_rest_user, i.e. the test setup superuser + xpack.rollup.put_job: + id: foo + body: > + { + "index_pattern": "foo", + "rollup_index": "foo_rollup", + "cron": "*/30 * * * * ?", + "page_size" :10, + "groups" : { + "date_histogram": { + "field": "the_field", + "interval": "1h" + } + }, + "metrics": [ + { + "field": "field_doesnt_exist", + "metrics": ["min", "max", "sum"] + } + ] + } From 9a8a1fdf293341c707abeb8af0bbb4f1061828bc Mon Sep 17 00:00:00 2001 From: lcawl Date: Mon, 4 Jun 2018 11:25:32 -0700 Subject: [PATCH 18/21] [DOCS] Removes duplicated authentication pages --- .../active-directory-realm.asciidoc | 78 --------- .../authentication/built-in-users.asciidoc | 157 ------------------ .../authentication/file-realm.asciidoc | 27 --- .../authentication/internal-users.asciidoc | 13 -- .../authentication/ldap-realm.asciidoc | 86 ---------- .../authentication/native-realm.asciidoc | 31 ---- .../security/authentication/overview.asciidoc | 64 ------- .../authentication/pki-realm.asciidoc | 21 --- .../security/authentication/realms.asciidoc | 124 -------------- .../authentication/saml-realm.asciidoc | 41 ----- .../docs/en/security/getting-started.asciidoc | 39 ----- .../en/security/how-security-works.asciidoc | 98 ----------- x-pack/docs/en/security/index.asciidoc | 123 -------------- 13 files changed, 902 deletions(-) delete mode 100644 x-pack/docs/en/security/authentication/active-directory-realm.asciidoc delete mode 100644 x-pack/docs/en/security/authentication/built-in-users.asciidoc delete mode 100644 x-pack/docs/en/security/authentication/file-realm.asciidoc delete mode 100644 x-pack/docs/en/security/authentication/internal-users.asciidoc delete mode 100644 x-pack/docs/en/security/authentication/ldap-realm.asciidoc delete mode 100644 x-pack/docs/en/security/authentication/native-realm.asciidoc delete mode 100644 x-pack/docs/en/security/authentication/overview.asciidoc delete mode 100644 x-pack/docs/en/security/authentication/pki-realm.asciidoc delete mode 100644 x-pack/docs/en/security/authentication/realms.asciidoc delete mode 100644 x-pack/docs/en/security/authentication/saml-realm.asciidoc delete mode 100644 x-pack/docs/en/security/getting-started.asciidoc delete mode 100644 x-pack/docs/en/security/how-security-works.asciidoc delete mode 100644 x-pack/docs/en/security/index.asciidoc diff --git a/x-pack/docs/en/security/authentication/active-directory-realm.asciidoc b/x-pack/docs/en/security/authentication/active-directory-realm.asciidoc deleted file mode 100644 index c0461f4f33885..0000000000000 --- a/x-pack/docs/en/security/authentication/active-directory-realm.asciidoc +++ /dev/null @@ -1,78 +0,0 @@ -[role="xpack"] -[[active-directory-realm]] -=== Active Directory user authentication - -You can configure {security} to communicate with Active Directory to authenticate -users. To integrate with Active Directory, you configure an `active_directory` -realm and map Active Directory users and groups to {security} roles in the -<>. - -See {ref}/configuring-ad-realm.html[Configuring an Active Directory Realm]. - -{security} uses LDAP to communicate with Active Directory, so `active_directory` -realms are similar to <>. Like LDAP directories, -Active Directory stores users and groups hierarchically. The directory's -hierarchy is built from containers such as the _organizational unit_ (`ou`), -_organization_ (`o`), and _domain controller_ (`dc`). - -The path to an entry is a _Distinguished Name_ (DN) that uniquely identifies a -user or group. User and group names typically have attributes such as a -_common name_ (`cn`) or _unique ID_ (`uid`). A DN is specified as a string, for -example `"cn=admin,dc=example,dc=com"` (white spaces are ignored). - -{security} only supports Active Directory security groups. You cannot map -distribution groups to roles. - -NOTE: When you use Active Directory for authentication, the username entered by - the user is expected to match the `sAMAccountName` or `userPrincipalName`, - not the common name. - -The Active Directory realm authenticates users using an LDAP bind request. After -authenticating the user, the realm then searches to find the user's entry in -Active Directory. Once the user has been found, the Active Directory realm then -retrieves the user's group memberships from the `tokenGroups` attribute on the -user's entry in Active Directory. - -[[ad-load-balancing]] -==== Load balancing and failover -The `load_balance.type` setting can be used at the realm level to configure how -{security} should interact with multiple Active Directory servers. Two modes of -operation are supported: failover and load balancing. - -See {ref}/security-settings.html#load-balancing[Load Balancing and Failover Settings]. - -[[ad-settings]] -==== Active Directory realm settings - -See {ref}/security-settings.html#ref-ad-settings[Active Directory Realm Settings]. - -[[mapping-roles-ad]] -==== Mapping Active Directory users and groups to roles - -See {ref}/configuring-ad-realm.html[Configuring an Active Directory realm]. - -[[ad-user-metadata]] -==== User metadata in Active Directory realms -When a user is authenticated via an Active Directory realm, the following -properties are populated in the user's _metadata_: - -|======================= -| Field | Description -| `ldap_dn` | The distinguished name of the user. -| `ldap_groups` | The distinguished name of each of the groups that were - resolved for the user (regardless of whether those - groups were mapped to a role). -|======================= - -This metadata is returned in the -{ref}/security-api-authenticate.html[authenticate API] and can be used with -<> in roles. - -Additional metadata can be extracted from the Active Directory server by configuring -the `metadata` setting on the Active Directory realm. - -[[active-directory-ssl]] -==== Setting up SSL between Elasticsearch and Active Directory - -See -{ref}/configuring-tls.html#tls-active-directory[Encrypting communications between {es} and Active Directory]. diff --git a/x-pack/docs/en/security/authentication/built-in-users.asciidoc b/x-pack/docs/en/security/authentication/built-in-users.asciidoc deleted file mode 100644 index d18f441e293f1..0000000000000 --- a/x-pack/docs/en/security/authentication/built-in-users.asciidoc +++ /dev/null @@ -1,157 +0,0 @@ -[role="xpack"] -[[built-in-users]] -=== Built-in users - -{security} provides built-in user credentials to help you get up and running. -These users have a fixed set of privileges and cannot be authenticated until their -passwords have been set. The `elastic` user can be used to -<>. - -`elastic`:: A built-in _superuser_. See <>. -`kibana`:: The user Kibana uses to connect and communicate with Elasticsearch. -`logstash_system`:: The user Logstash uses when storing monitoring information in Elasticsearch. -`beats_system`:: The user the Beats use when storing monitoring information in Elasticsearch. - - -[float] -[[built-in-user-explanation]] -==== How the built-in users work -These built-in users are stored within a special `.security` index managed by -{security}. -This means that, if the password is changed, or a user is disabled, then that -change is automatically reflected on each node in the cluster. It also means -that if your `.security` index is deleted, or restored from a snapshot, then -any changes you have applied will be lost. - -Although they share the same API, the built-in users are separate and distinct -from users managed by the <>. Disabling the native -realm will not have any effect on the built-in users. The built-in users can -be disabled individually, using the -{ref}/security-api-users.html[user management API]. - -[float] -[[bootstrap-elastic-passwords]] -==== The Elastic bootstrap password - -When you install {es}, if the `elastic` user does not already have a password, -it uses a default bootstrap password. The bootstrap password is a transient -password that enables you to run the tools that set all the built-in user passwords. - -By default, the bootstrap password is derived from a randomized `keystore.seed` -setting, which is added to the keystore during installation. You do not need -to know or change this bootstrap password. If you have defined a -`bootstrap.password` setting in the keystore, however, that value is used instead. -For more information about interacting with the keystore, see -{ref}/secure-settings.html[Secure Settings]. - -NOTE: After you <>, -in particular for the `elastic` user, there is no further use for the bootstrap -password. - -[float] -[[set-built-in-user-passwords]] -==== Setting built-in user passwords - -You must set the passwords for all built-in users. - -The +elasticsearch-setup-passwords+ tool is the simplest method to set the -built-in users' passwords for the first time. It uses the `elastic` user's -bootstrap password to run user management API requests. For example, you can run -the command in an "interactive" mode, which prompts you to enter new passwords -for the `elastic`, `kibana`, `logstash_system`, and `beats_system` users: - -[source,shell] --------------------------------------------------- -bin/elasticsearch-setup-passwords interactive --------------------------------------------------- - -For more information about the command options, see -{ref}/setup-passwords.html[elasticsearch-setup-passwords]. - -IMPORTANT: After you set a password for the `elastic` user, the bootstrap -password is no longer valid; you cannot run the `elasticsearch-setup-passwords` -command a second time. - -Alternatively, you can set the initial passwords for the built-in users by using -the *Management > Users* page in {kib} or the -{ref}/security-api-change-password.html[Change Password API]. These methods are -more complex. You must supply the `elastic` user and its bootstrap password to -log into {kib} or run the API. This requirement means that you cannot use the -default bootstrap password that is derived from the `keystore.seed` setting. -Instead, you must explicitly set a `bootstrap.password` setting in the keystore -before you start {es}. For example, the following command prompts you to enter a -new bootstrap password: - -[source,shell] ----------------------------------------------------- -bin/elasticsearch-keystore add "bootstrap.password" ----------------------------------------------------- - -You can then start {es} and {kib} and use the `elastic` user and bootstrap -password to log into {kib} and change the passwords. Alternatively, you can -submit Change Password API requests for each built-in user. These methods are -better suited for changing your passwords after the initial setup is complete, -since at that point the bootstrap password is no longer required. - -[float] -[[add-built-in-user-passwords]] -==== Adding Built-in User Passwords To {kib}, Logstash, and Beats - -After the `kibana` user password is set, you need to update the {kib} server -with the new password by setting `elasticsearch.password` in the `kibana.yml` -configuration file: - -[source,yaml] ------------------------------------------------ -elasticsearch.password: kibanapassword ------------------------------------------------ - -The `logstash_system` user is used internally within Logstash when -monitoring is enabled for Logstash. - -To enable this feature in Logstash, you need to update the Logstash -configuration with the new password by setting `xpack.monitoring.elasticsearch.password` in -the `logstash.yml` configuration file: - -[source,yaml] ----------------------------------------------------------- -xpack.monitoring.elasticsearch.password: logstashpassword ----------------------------------------------------------- - -If you have upgraded from an older version of Elasticsearch, -the `logstash_system` user may have defaulted to _disabled_ for security reasons. -Once the password has been changed, you can enable the user via the following API call: - -[source,js] ---------------------------------------------------------------------- -PUT _xpack/security/user/logstash_system/_enable ---------------------------------------------------------------------- -// CONSOLE - -The `beats_system` user is used internally within Beats when monitoring is -enabled for Beats. - -To enable this feature in Beats, you need to update the configuration for each -of your beats to reference the correct username and password. For example: - -[source,yaml] ----------------------------------------------------------- -xpack.monitoring.elasticsearch.username: beats_system -xpack.monitoring.elasticsearch.password: beatspassword ----------------------------------------------------------- - -If you have upgraded from an older version of {es}, then you may not have set a -password for the `beats_system` user. If this is the case, then you should use -the *Management > Users* page in {kib} or the -{ref}/security-api-change-password.html[Change Password API] to set a password -for this user. - -[float] -[[disabling-default-password]] -==== Disabling default password functionality -[IMPORTANT] -============================================================================= -This setting is deprecated. The elastic user no longer has a default password. -The password must be set before the user can be used. -See <>. -============================================================================= diff --git a/x-pack/docs/en/security/authentication/file-realm.asciidoc b/x-pack/docs/en/security/authentication/file-realm.asciidoc deleted file mode 100644 index 1161778bb801c..0000000000000 --- a/x-pack/docs/en/security/authentication/file-realm.asciidoc +++ /dev/null @@ -1,27 +0,0 @@ -[role="xpack"] -[[file-realm]] -=== File-based user authentication - -You can manage and authenticate users with the built-in `file` realm. -With the `file` realm, users are defined in local files on each node in the cluster. - -IMPORTANT: As the administrator of the cluster, it is your responsibility to - ensure the same users are defined on every node in the cluster. - {security} does not deliver any mechanism to guarantee this. - -The `file` realm is primarily supported to serve as a fallback/recovery realm. It -is mostly useful in situations where all users locked themselves out of the system -(no one remembers their username/password). In this type of scenarios, the `file` -realm is your only way out - you can define a new `admin` user in the `file` realm -and use it to log in and reset the credentials of all other users. - -IMPORTANT: When you configure realms in `elasticsearch.yml`, only the -realms you specify are used for authentication. To use the -`file` realm as a fallback, you must include it in the realm chain. - -To define users, {security} provides the {ref}/users-command.html[users] -command-line tool. This tool enables you to add and remove users, assign user -roles, and manage user passwords. - -For more information, see -{ref}/configuring-file-realm.html[Configuring a file realm]. diff --git a/x-pack/docs/en/security/authentication/internal-users.asciidoc b/x-pack/docs/en/security/authentication/internal-users.asciidoc deleted file mode 100644 index 77571a53a56f3..0000000000000 --- a/x-pack/docs/en/security/authentication/internal-users.asciidoc +++ /dev/null @@ -1,13 +0,0 @@ -[role="xpack"] -[[internal-users]] -=== Internal users - -{security} has three _internal_ users (`_system`, `_xpack`, and `_xpack_security`) -that are responsible for the operations that take place inside an {es} cluster. - -These users are only used by requests that originate from within the cluster. -For this reason, they cannot be used to authenticate against the API and there -is no password to manage or reset. - -From time-to-time you may find a reference to one of these users inside your -logs, including <>. diff --git a/x-pack/docs/en/security/authentication/ldap-realm.asciidoc b/x-pack/docs/en/security/authentication/ldap-realm.asciidoc deleted file mode 100644 index 02d0162a9c9f9..0000000000000 --- a/x-pack/docs/en/security/authentication/ldap-realm.asciidoc +++ /dev/null @@ -1,86 +0,0 @@ -[role="xpack"] -[[ldap-realm]] -=== LDAP user authentication - -You can configure {security} to communicate with a Lightweight Directory Access -Protocol (LDAP) server to authenticate users. To integrate with LDAP, you -configure an `ldap` realm and map LDAP groups to user roles in the -<>. - -LDAP stores users and groups hierarchically, similar to the way folders are -grouped in a file system. An LDAP directory's hierarchy is built from containers -such as the _organizational unit_ (`ou`), _organization_ (`o`), and -_domain controller_ (`dc`). - -The path to an entry is a _Distinguished Name_ (DN) that uniquely identifies a -user or group. User and group names typically have attributes such as a -_common name_ (`cn`) or _unique ID_ (`uid`). A DN is specified as a string, -for example `"cn=admin,dc=example,dc=com"` (white spaces are ignored). - -The `ldap` realm supports two modes of operation, a user search mode -and a mode with specific templates for user DNs. - -[[ldap-user-search]] -==== User search mode and user DN templates mode - -See {ref}/configuring-ldap-realm.html[Configuring an LDAP Realm]. - -[[ldap-load-balancing]] -==== Load balancing and failover -The `load_balance.type` setting can be used at the realm level to configure how -{security} should interact with multiple LDAP servers. {security} supports both -failover and load balancing modes of operation. - -See {ref}/security-settings.html#load-balancing[Load Balancing and Failover Settings]. - -[[ldap-settings]] -==== LDAP realm settings - -See {ref}/security-settings.html#ref-ldap-settings[LDAP Realm Settings]. - -[[mapping-roles-ldap]] -==== Mapping LDAP groups to roles - -An integral part of a realm authentication process is to resolve the roles -associated with the authenticated user. Roles define the privileges a user has -in the cluster. - -Since with the `ldap` realm the users are managed externally in the LDAP server, -the expectation is that their roles are managed there as well. If fact, LDAP -supports the notion of groups, which often represent user roles for different -systems in the organization. - -The `ldap` realm enables you to map LDAP users to to roles via their LDAP -groups, or other metadata. This role mapping can be configured via the -{ref}/security-api-role-mapping.html[role-mapping API], or by using a file stored -on each node. When a user authenticates with LDAP, the privileges -for that user are the union of all privileges defined by the roles to which -the user is mapped. For more information, see -{ref}/configuring-ldap-realm.html[Configuring an LDAP Realm]. - -[[ldap-user-metadata]] -==== User metadata in LDAP realms -When a user is authenticated via an LDAP realm, the following properties are -populated in the user's _metadata_: - -|======================= -| Field | Description -| `ldap_dn` | The distinguished name of the user. -| `ldap_groups` | The distinguished name of each of the groups that were - resolved for the user (regardless of whether those - groups were mapped to a role). -|======================= - -This metadata is returned in the -{ref}/security-api-authenticate.html[authenticate API], and can be used with -<> in roles. - -Additional fields can be included in the user's metadata by configuring -the `metadata` setting on the LDAP realm. This metadata is available for use -with the <> or in -<>. - -[[ldap-ssl]] -==== Setting up SSL Between Elasticsearch and LDAP - -See {ref}/configuring-tls.html#tls-ldap[Encrypting Communications Between {es} and LDAP]. diff --git a/x-pack/docs/en/security/authentication/native-realm.asciidoc b/x-pack/docs/en/security/authentication/native-realm.asciidoc deleted file mode 100644 index 6aa0a72fc8495..0000000000000 --- a/x-pack/docs/en/security/authentication/native-realm.asciidoc +++ /dev/null @@ -1,31 +0,0 @@ -[role="xpack"] -[[native-realm]] -=== Native user authentication - -The easiest way to manage and authenticate users is with the internal `native` -realm. You can use the REST APIs or Kibana to add and remove users, assign user roles, and -manage user passwords. - -[[native-realm-configuration]] -[float] -==== Configuring a native realm - -See {ref}/configuring-native-realm.html[Configuring a native realm]. - -[[native-settings]] -==== Native realm settings - -See {ref}/security-settings.html#ref-native-settings[Native realm settings]. - -[[managing-native-users]] -==== Managing native users - -{security} enables you to easily manage users in {kib} on the -*Management / Security / Users* page. - -Alternatively, you can manage users through the `user` API. For more -information and examples, see {ref}/security-api-users.html[User management APIs]. - -[[migrating-from-file]] -NOTE: To migrate file-based users to the `native` realm, use the -{ref}/migrate-tool.html[migrate tool]. diff --git a/x-pack/docs/en/security/authentication/overview.asciidoc b/x-pack/docs/en/security/authentication/overview.asciidoc deleted file mode 100644 index 7633f02b6765b..0000000000000 --- a/x-pack/docs/en/security/authentication/overview.asciidoc +++ /dev/null @@ -1,64 +0,0 @@ -[role="xpack"] -[[setting-up-authentication]] -== User authentication - -Authentication identifies an individual. To gain access to restricted resources, -a user must prove their identity, via passwords, credentials, or some other -means (typically referred to as authentication tokens). - -The {stack} authenticates users by identifying the users behind the requests -that hit the cluster and verifying that they are who they claim to be. The -authentication process is handled by one or more authentication services called -<>. - -You can use the native support for managing and authenticating users, or -integrate with external user management systems such as LDAP and Active -Directory. - -{security} provides built-in realms such as `native`,`ldap`, `active_directory`, -`pki`, `file`, and `saml`. If none of the built-in realms meet your needs, you -can also build your own custom realm and plug it into the {stack}. - -When {security} is enabled, depending on the realms you've configured, you must -attach your user credentials to the requests sent to {es}. For example, when -using realms that support usernames and passwords you can simply attach -{wikipedia}/Basic_access_authentication[basic auth] header to the requests. - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/built-in-users.asciidoc -include::built-in-users.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/internal-users.asciidoc -include::internal-users.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/realms.asciidoc -include::realms.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/active-directory-realm.asciidoc -include::active-directory-realm.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/file-realm.asciidoc -include::file-realm.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/ldap-realm.asciidoc -include::ldap-realm.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/native-realm.asciidoc -include::native-realm.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/pki-realm.asciidoc -include::pki-realm.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/saml-realm.asciidoc -include::saml-realm.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/custom-realm.asciidoc -include::custom-realm.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/anonymous-access.asciidoc -include::anonymous-access.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/user-cache.asciidoc -include::user-cache.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/saml-guide.asciidoc -include::saml-guide.asciidoc[] diff --git a/x-pack/docs/en/security/authentication/pki-realm.asciidoc b/x-pack/docs/en/security/authentication/pki-realm.asciidoc deleted file mode 100644 index 6ce9b0e0770a4..0000000000000 --- a/x-pack/docs/en/security/authentication/pki-realm.asciidoc +++ /dev/null @@ -1,21 +0,0 @@ -[role="xpack"] -[[pki-realm]] -=== PKI user authentication - -You can configure {security} to use Public Key Infrastructure (PKI) certificates -to authenticate users in {es}. This requires clients to present X.509 -certificates. - -NOTE: You cannot use PKI certificates to authenticate users in {kib}. - -To use PKI in {es}, you configure a PKI realm, enable client authentication on -the desired network layers (transport or http), and map the Distinguished Names -(DNs) from the user certificates to {security} roles in the -<>. - -See {ref}/configuring-pki-realm.html[Configuring a PKI realm]. - -[[pki-settings]] -==== PKI realm settings - -See {ref}/security-settings.html#ref-pki-settings[PKI realm settings]. diff --git a/x-pack/docs/en/security/authentication/realms.asciidoc b/x-pack/docs/en/security/authentication/realms.asciidoc deleted file mode 100644 index ec0945b5a113c..0000000000000 --- a/x-pack/docs/en/security/authentication/realms.asciidoc +++ /dev/null @@ -1,124 +0,0 @@ -[role="xpack"] -[[realms]] -=== Realms - -Authentication in {security} is handled by one or more authentication services -called _realms_. A _realm_ is used to resolve and authenticate users based on -authentication tokens. {security} provides the following built-in realms: - -_native_:: -An internal realm where users are stored in a dedicated {es} index. -This realm supports an authentication token in the form of username and password, -and is available by default when no realms are explicitly configured. The users -are managed via the {ref}/security-api-users.html[User Management API]. See -<>. - -_ldap_:: -A realm that uses an external LDAP server to authenticate the -users. This realm supports an authentication token in the form of username and -password, and requires explicit configuration in order to be used. See -<>. - -_active_directory_:: -A realm that uses an external Active Directory Server to authenticate the -users. With this realm, users are authenticated by usernames and passwords. -See <>. - -_pki_:: -A realm that authenticates users using Public Key Infrastructure (PKI). This -realm works in conjunction with SSL/TLS and identifies the users through the -Distinguished Name (DN) of the client's X.509 certificates. See <>. - -_file_:: -An internal realm where users are defined in files stored on each node in the -{es} cluster. This realm supports an authentication token in the form -of username and password and is always available. See <>. - -_saml_:: -A realm that facilitates authentication using the SAML 2.0 Web SSO protocol. -This realm is designed to support authentication through {kib} and is not -intended for use in the REST API. See <>. - -{security} also supports custom realms. If you need to integrate with another -authentication system, you can build a custom realm plugin. For more information, -see <>. - -Realms live within a _realm chain_. It is essentially a prioritized list of -configured realms (typically of various types). The order of the list determines -the order in which the realms will be consulted. You should make sure each -configured realm has a distinct `order` setting. In the event that two or more -realms have the same `order`, they will be processed in `name` order. -During the authentication process, {security} will consult and try to -authenticate the request one realm at a time. -Once one of the realms successfully authenticates the request, the authentication -is considered to be successful and the authenticated user will be associated -with the request (which will then proceed to the authorization phase). If a realm -cannot authenticate the request, the next in line realm in the chain will be -consulted. If all realms in the chain could not authenticate the request, the -authentication is then considered to be unsuccessful and an authentication error -will be returned (as HTTP status code `401`). - -NOTE: Some systems (e.g. Active Directory) have a temporary lock-out period after - several successive failed login attempts. If the same username exists in - multiple realms, unintentional account lockouts are possible. For more - information, please see <>. - -The default realm chain contains the `native` and `file` realms. To explicitly, -configure a realm chain, you specify the chain in `elasticsearch.yml`. When you -configure a realm chain, only the realms you specify are used for authentication. -To use the `native` and `file` realms, you must include them in the chain. - -The following snippet configures a realm chain that includes the `file` and -`native` realms, as well as two LDAP realms and an Active Directory realm. - -[source,yaml] ----------------------------------------- -xpack.security.authc: - realms: - - file: - type: file - order: 0 - - native: - type: native - order: 1 - - ldap1: - type: ldap - order: 2 - enabled: false - url: 'url_to_ldap1' - ... - - ldap2: - type: ldap - order: 3 - url: 'url_to_ldap2' - ... - - ad1: - type: active_directory - order: 4 - url: 'url_to_ad' ----------------------------------------- - -As can be seen above, each realm has a unique name that identifies it and each -realm type dictates its own set of required and optional settings. That said, -there are -{ref}/security-settings.html#ref-realm-settings[settings that are common to all realms]. - -Realm types can roughly be classified in two categories: - -Internal:: Realms that are internal to Elasticsearch and don't require any - communication with external parties. They are fully managed by - {security}. There can only be a maximum of one configured realm - per internal realm type. {security} provides two internal realm - types: `native` and `file`. - -External:: Realms that require interaction with parties/components external to - {es}, typically, with enterprise grade identity management - systems. Unlike internal realms, there can be as many external realms - as one would like - each with its own unique name and configuration. - {security} provides the following external realm types: `ldap`, - `active_directory`, `saml`, and `pki`. diff --git a/x-pack/docs/en/security/authentication/saml-realm.asciidoc b/x-pack/docs/en/security/authentication/saml-realm.asciidoc deleted file mode 100644 index a55ae270a19a1..0000000000000 --- a/x-pack/docs/en/security/authentication/saml-realm.asciidoc +++ /dev/null @@ -1,41 +0,0 @@ -[role="xpack"] -[[saml-realm]] -=== SAML authentication -{security} supports user authentication using SAML Single Sign On. -{security} provides this support using the Web Browser SSO profile of the SAML -2.0 protocol. - -This protocol is specifically designed to support authentication via an -interactive web browser, so it does not operate as a standard authentication -realm. Instead, {security} provides features in {kib} and {es} that work -together to enable interactive SAML sessions. - -This means that the SAML realm is not suitable for use by standard REST clients. -If you configure a SAML realm for use in {kib}, you should also configure -another realm, such as the <> in your authentication -chain. - -In order to simplify the process of configuring SAML authentication within the -Elastic Stack, there is a step-by-step guide to -<>. - -The remainder of this document will describe {es} specific configuration options -for SAML realms. - -[[saml-settings]] -==== SAML realm settings - -See {ref}/security-settings.html#ref-saml-settings[SAML Realm Settings]. - -==== SAML realm signing settings - -See {ref}/security-settings.html#ref-saml-signing-settings[SAML Realm Signing Settings]. - -==== SAML realm encryption settings - -See {ref}/security-settings.html#ref-saml-encryption-settings[SAML Realm Encryption Settings]. - -==== SAML realm SSL settings - -See {ref}/security-settings.html#ref-saml-ssl-settings[SAML Realm SSL Settings]. - diff --git a/x-pack/docs/en/security/getting-started.asciidoc b/x-pack/docs/en/security/getting-started.asciidoc deleted file mode 100644 index b8f1183cddf89..0000000000000 --- a/x-pack/docs/en/security/getting-started.asciidoc +++ /dev/null @@ -1,39 +0,0 @@ -[role="xpack"] -[[security-getting-started]] -== Getting started with security - -To secure a cluster, you must enable {security} on every node in the -cluster. Basic authentication is enabled by default--to communicate -with the cluster, you must specify a username and password. -Unless you {xpack-ref}/anonymous-access.html[enable anonymous access], all -requests that don't include a user name and password are rejected. - -To get started with {security}: - -. {ref}/configuring-security.html[Configure security in {es}]. Encrypt -inter-node communications, set passwords for the -<>, and manage your users and roles. - -. {kibana-ref}/using-kibana-with-security.html[Configure security in {kib}]. -Set the authentication credentials in {kib} and encrypt communications between -the browser and the {kib} server. - -. {logstash-ref}/ls-security.html[Configure security in Logstash]. Set the -authentication credentials for Logstash and encrypt communications between -Logstash and {es}. - -. <>. Configure authentication -credentials and encrypt connections to {es}. - -. Configure the Java transport client to use encrypted communications. -See <>. - -. Configure {es} for Apache Hadoop to use secured transport. See -{hadoop-ref}/security.html[{es} for Apache Hadoop Security]. - -Depending on your security requirements, you might also want to: - -* Integrate with {xpack-ref}/ldap-realm.html[LDAP] or {xpack-ref}/active-directory-realm.html[Active Directory], -or {xpack-ref}/pki-realm.html[require certificates] for authentication. -* Use {xpack-ref}/ip-filtering.html[IP Filtering] to allow or deny requests from particular -IP addresses or address ranges. diff --git a/x-pack/docs/en/security/how-security-works.asciidoc b/x-pack/docs/en/security/how-security-works.asciidoc deleted file mode 100644 index dcc152c2bcaab..0000000000000 --- a/x-pack/docs/en/security/how-security-works.asciidoc +++ /dev/null @@ -1,98 +0,0 @@ -[role="xpack"] -[[how-security-works]] -== How security works - -An Elasticsearch cluster is typically made out of many moving parts. There are -the Elasticsearch nodes that form the cluster, and often Logstash instances, -Kibana instances, Beats agents an clients, all communicating with the it. -It should not come as a surprise that securing such clusters has many facets and -layers. - -{security} provides the means to secure the Elastic cluster on several levels: - - * <> - * Authorization and Role Based Access Control (a.k.a RBAC) - * Node/Client Authentication and Channel Encryption - * Auditing - -[float] -=== Authorization - -The authorization process takes place once a request is authenticated and the -User behind the request is identified. Authorization is the process of determining -whether the user behind an incoming request is allowed to execute it. Naturally, -this process takes place right after an successful authentication - when the -user identity is known. - -The authorization process revolves around the following 5 constructs: - -_Secured Resource_:: -A resource to which access is restricted. Indices/aliases, documents, fields, -users and the Elasticsearch cluster itself are all examples of secured objects. - -_Privilege_:: -A named group representing one or more actions that a user may execute against a -secured resource. Each secured resource has its own sets of available privileges. -For example, `read` is an index privilege that represents all actions that enable -reading the indexed/stored data. For a complete list of available privileges -see <>. - -_Permissions_:: -A set of one or more privileges against a secured resource. Permissions can -easily be described in words, here are few examples: - * `read` privilege on the `products` index - * `manage` privilege on the cluster - * `run_as` privilege on `john` user - * `read` privilege on documents that match query X - * `read` privilege on `credit_card` field - -_Role_:: -A named sets of permissions - -_User_:: -The authenticated user. - -A secure Elasticsearch cluster manages the privileges of users through _roles_. -A role has a unique name and identifies a set of permissions that translate to -privileges on resources. A user can be associated with an arbitrary number of -roles. The total set of permissions that a user has is therefore defined by -union of the permissions in all its roles. - -Roles can be assigned to users in a number of ways depending on the realms by -which the users are authenticated. - -For more information on user authentication see <> - - -[float] -=== Node/client authentication and channel encryption - -{security} supports configuring SSL/TLS for securing the communication channels -to, from and within the cluster. This support accounts for: - - * Encryption of data transmitted over the wires - * Certificate based node authentication - preventing unauthorized nodes/clients - from establishing a connection with the cluster. - -For more information, see <>. - -{security} also enables you to <> which can -be seen as a light mechanism for node/client authentication. With IP Filtering -you can restrict the nodes and clients that can connect to the cluster based -on their IP addresses. The IP filters configuration provides whitelisting -and blacklisting of IPs, subnets and DNS domains. - - -[float] -=== Auditing -When dealing with any secure system, it is critical to have a audit trail -mechanism set in place. Audit trails log various activities/events that occur in -the system, enabling you to analyze and back track past events when things go -wrong (e.g. security breach). - -{security} provides such audit trail functionality for all nodes in the cluster. -You can configure the audit level which accounts for the type of events that are -logged. These events include failed authentication attempts, user access denied, -node connection denied, and more. - -For more information on auditing see <>. diff --git a/x-pack/docs/en/security/index.asciidoc b/x-pack/docs/en/security/index.asciidoc deleted file mode 100644 index 460932679de8f..0000000000000 --- a/x-pack/docs/en/security/index.asciidoc +++ /dev/null @@ -1,123 +0,0 @@ -[role="xpack"] -[[xpack-security]] -= Securing the {stack} - -[partintro] --- -{security} enables you to easily secure a cluster. With {security}, -you can password-protect your data as well as implement more advanced security -measures such as encrypting communications, role-based access control, -IP filtering, and auditing. This guide describes how to configure the security -features you need, and interact with your secured cluster. - -Security protects Elasticsearch clusters by: - -* <> - with password protection, role-based access control, and IP filtering. -* <> - with message authentication and SSL/TLS encryption. -* <> - so you know who's doing what to your cluster and the data it stores. - -[float] -[[preventing-unauthorized-access]] -=== Preventing Unauthorized Access - -To prevent unauthorized access to your Elasticsearch cluster, you must have a -way to _authenticate_ users. This simply means that you need a way to validate -that a user is who they claim to be. For example, you have to make sure only -the person named _Kelsey Andorra_ can sign in as the user `kandorra`. {security} -provides a standalone authentication mechanism that enables you to -quickly password-protect your cluster. If you're already using <>, -<>, or <> to manage -users in your organization, {security} is able to integrate with those -systems to perform user authentication. - -In many cases, simply authenticating users isn't enough. You also need a way to -control what data users have access to and what tasks they can perform. {security} -enables you to _authorize_ users by assigning access _privileges_ to _roles_, -and assigning those roles to users. For example, this -<> mechanism (a.k.a RBAC) enables -you to specify that the user `kandorra` can only perform read operations on the -`events` index and can't do anything at all with other indices. - -{security} also supports <>. You can -whitelist and blacklist specific IP addresses or subnets to control network-level -access to a server. - -[float] -[[preserving-data-integrity]] -=== Preserving Data Integrity - -A critical part of security is keeping confidential data confidential. -Elasticsearch has built-in protections against accidental data loss and -corruption. However, there's nothing to stop deliberate tampering or data -interception. {security} preserves the integrity of your data by -<> to and from nodes. -For even greater protection, you can increase the <> and -<>. - - -[float] -[[maintaining-audit-trail]] -=== Maintaining an Audit Trail - -Keeping a system secure takes vigilance. By using {security} to maintain -an audit trail, you can easily see who is accessing your cluster and what they're -doing. By analyzing access patterns and failed attempts to access your cluster, -you can gain insights into attempted attacks and data breaches. Keeping an -auditable log of the activity in your cluster can also help diagnose operational -issues. - -[float] -=== Where to Go Next - -* <> - steps through how to install and start using Security for basic authentication. - -* <> - provides more information about how Security supports user authentication, - authorization, and encryption. - -* <> - shows you how to interact with an Elasticsearch cluster protected by - {security}. - -* <> - provides detailed information about the access privileges you can grant to - users, the settings you can configure for Security in `elasticsearch.yml`, - and the files where Security configuration information is stored. - -[float] -=== Have Comments, Questions, or Feedback? - -Head over to our {security-forum}[Security Discussion Forum] -to share your experience, questions, and suggestions. --- - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/getting-started.asciidoc -include::getting-started.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/how-security-works.asciidoc -include::how-security-works.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authentication/overview.asciidoc -include::authentication/overview.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/authorization/overview.asciidoc -include::authorization/overview.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/auditing/index.asciidoc -include::auditing/index.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/securing-communications.asciidoc -include::securing-communications.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/using-ip-filtering.asciidoc -include::using-ip-filtering.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/tribe-clients-integrations.asciidoc -include::tribe-clients-integrations.asciidoc[] - -:edit_url: https://github.com/elastic/elasticsearch/edit/{branch}/x-pack/docs/en/security/reference.asciidoc -include::reference.asciidoc[] From 11b001dea1058071329373dd5812d6d72def7486 Mon Sep 17 00:00:00 2001 From: Julie Tibshirani Date: Mon, 4 Jun 2018 08:42:32 -0700 Subject: [PATCH 19/21] Make sure KeywordFieldMapper#clone preserves split_queries_on_whitespace. (#31049) (cherry picked from commit 30a8f9d948050a2ca0fb93499471d8aee782c774) --- .../index/mapper/KeywordFieldMapper.java | 2 +- .../index/mapper/KeywordFieldTypeTests.java | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java index de9283159038b..08abf5bc68d2c 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/KeywordFieldMapper.java @@ -198,7 +198,7 @@ public KeywordFieldType() { protected KeywordFieldType(KeywordFieldType ref) { super(ref); this.normalizer = ref.normalizer; - this.splitQueriesOnWhitespace = splitQueriesOnWhitespace; + this.splitQueriesOnWhitespace = ref.splitQueriesOnWhitespace; } public KeywordFieldType clone() { diff --git a/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldTypeTests.java b/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldTypeTests.java index 809ceb5831004..a291062c7a5bf 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldTypeTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/KeywordFieldTypeTests.java @@ -52,8 +52,15 @@ public class KeywordFieldTypeTests extends FieldTypeTestCase { public void setupProperties() { addModifier(new Modifier("normalizer", false) { @Override - public void modify(MappedFieldType ft) { - ((KeywordFieldType) ft).setNormalizer(Lucene.KEYWORD_ANALYZER); + public void modify(MappedFieldType type) { + ((KeywordFieldType) type).setNormalizer(Lucene.KEYWORD_ANALYZER); + } + }); + addModifier(new Modifier("split_queries_on_whitespace", true) { + @Override + public void modify(MappedFieldType type) { + KeywordFieldType keywordType = (KeywordFieldType) type; + keywordType.setSplitQueriesOnWhitespace(!keywordType.splitQueriesOnWhitespace()); } }); } From 3bc5248051fdc709706548abc221ce6a15bcee5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20B=C3=BCscher?= Date: Mon, 4 Jun 2018 20:20:37 +0200 Subject: [PATCH 20/21] Change ObjectParser exception (#31030) ObjectParser should throw XContentParseExceptions, not IAE. A dedicated parsing exception can includes the place where the error occurred. Closes #30605 --- .../common/xcontent/ObjectParser.java | 7 +++--- .../common/xcontent/ObjectParserTests.java | 20 ++++++---------- .../DiscountedCumulativeGainTests.java | 7 +++--- .../rankeval/MeanReciprocalRankTests.java | 7 +++--- .../index/rankeval/PrecisionAtKTests.java | 7 +++--- .../index/rankeval/RatedDocumentTests.java | 7 +++--- .../ClusterUpdateSettingsRequestTests.java | 8 ++++--- .../action/update/UpdateRequestTests.java | 24 +++++++++++++++++++ .../highlight/HighlightBuilderTests.java | 18 +++++++------- .../rescore/QueryRescorerBuilderTests.java | 5 ++-- .../search/sort/FieldSortBuilderTests.java | 9 +++---- .../search/sort/ScriptSortBuilderTests.java | 13 +++++----- .../test/AbstractQueryTestCase.java | 14 +++++++---- .../core/ml/datafeed/DatafeedConfigTests.java | 7 +++--- .../xpack/core/ml/job/config/JobTests.java | 6 +++-- .../output/AutodetectResultsParserTests.java | 7 +++--- .../common/text/TextTemplateTests.java | 17 ++++--------- 17 files changed, 105 insertions(+), 78 deletions(-) diff --git a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/ObjectParser.java b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/ObjectParser.java index 71b888bf44acb..dfcc4271b922e 100644 --- a/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/ObjectParser.java +++ b/libs/x-content/src/main/java/org/elasticsearch/common/xcontent/ObjectParser.java @@ -155,7 +155,7 @@ public Value parse(XContentParser parser, Value value, Context context) throws I while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); - fieldParser = getParser(currentFieldName); + fieldParser = getParser(currentFieldName, parser); } else { if (currentFieldName == null) { throw new XContentParseException(parser.getTokenLocation(), "[" + name + "] no field found"); @@ -341,10 +341,11 @@ private void parseSub(XContentParser parser, FieldParser fieldParser, String cur } } - private FieldParser getParser(String fieldName) { + private FieldParser getParser(String fieldName, XContentParser xContentParser) { FieldParser parser = fieldParserMap.get(fieldName); if (parser == null && false == ignoreUnknownFields) { - throw new IllegalArgumentException("[" + name + "] unknown field [" + fieldName + "], parser not found"); + throw new XContentParseException(xContentParser.getTokenLocation(), + "[" + name + "] unknown field [" + fieldName + "], parser not found"); } return parser; } diff --git a/libs/x-content/src/test/java/org/elasticsearch/common/xcontent/ObjectParserTests.java b/libs/x-content/src/test/java/org/elasticsearch/common/xcontent/ObjectParserTests.java index 3dd33e997b2ea..6aa0a321adf4d 100644 --- a/libs/x-content/src/test/java/org/elasticsearch/common/xcontent/ObjectParserTests.java +++ b/libs/x-content/src/test/java/org/elasticsearch/common/xcontent/ObjectParserTests.java @@ -35,7 +35,6 @@ import java.util.Collections; import java.util.List; -import static org.hamcrest.CoreMatchers.startsWith; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasSize; @@ -186,7 +185,6 @@ public URI parseURI(XContentParser parser) { } public void testExceptions() throws IOException { - XContentParser parser = createParser(JsonXContent.jsonXContent, "{\"test\" : \"foo\"}"); class TestStruct { public void setTest(int test) { } @@ -195,20 +193,16 @@ public void setTest(int test) { TestStruct s = new TestStruct(); objectParser.declareInt(TestStruct::setTest, new ParseField("test")); - try { - objectParser.parse(parser, s, null); - fail("numeric value expected"); - } catch (XContentParseException ex) { + { + XContentParser parser = createParser(JsonXContent.jsonXContent, "{\"test\" : \"foo\"}"); + XContentParseException ex = expectThrows(XContentParseException.class, () -> objectParser.parse(parser, s, null)); assertThat(ex.getMessage(), containsString("[the_parser] failed to parse field [test]")); assertTrue(ex.getCause() instanceof NumberFormatException); } - - parser = createParser(JsonXContent.jsonXContent, "{\"not_supported_field\" : \"foo\"}"); - try { - objectParser.parse(parser, s, null); - fail("field not supported"); - } catch (IllegalArgumentException ex) { - assertEquals(ex.getMessage(), "[the_parser] unknown field [not_supported_field], parser not found"); + { + XContentParser parser = createParser(JsonXContent.jsonXContent, "{\"not_supported_field\" : \"foo\"}"); + XContentParseException ex = expectThrows(XContentParseException.class, () -> objectParser.parse(parser, s, null)); + assertEquals(ex.getMessage(), "[1:2] [the_parser] unknown field [not_supported_field], parser not found"); } } diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainTests.java index ba03a734ec760..64337786b1eb6 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/DiscountedCumulativeGainTests.java @@ -25,6 +25,7 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; @@ -41,7 +42,7 @@ import static org.elasticsearch.index.rankeval.EvaluationMetric.filterUnknownDocuments; import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; import static org.elasticsearch.test.XContentTestUtils.insertRandomFields; -import static org.hamcrest.Matchers.startsWith; +import static org.hamcrest.CoreMatchers.containsString; public class DiscountedCumulativeGainTests extends ESTestCase { @@ -280,9 +281,9 @@ public void testXContentParsingIsNotLenient() throws IOException { try (XContentParser parser = createParser(xContentType.xContent(), withRandomFields)) { parser.nextToken(); parser.nextToken(); - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, + XContentParseException exception = expectThrows(XContentParseException.class, () -> DiscountedCumulativeGain.fromXContent(parser)); - assertThat(exception.getMessage(), startsWith("[dcg_at] unknown field")); + assertThat(exception.getMessage(), containsString("[dcg_at] unknown field")); } } diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/MeanReciprocalRankTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/MeanReciprocalRankTests.java index a5597873103bc..f88b0cc663489 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/MeanReciprocalRankTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/MeanReciprocalRankTests.java @@ -25,6 +25,7 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; @@ -41,7 +42,7 @@ import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; import static org.elasticsearch.test.XContentTestUtils.insertRandomFields; -import static org.hamcrest.Matchers.startsWith; +import static org.hamcrest.CoreMatchers.containsString; public class MeanReciprocalRankTests extends ESTestCase { @@ -189,9 +190,9 @@ public void testXContentParsingIsNotLenient() throws IOException { try (XContentParser parser = createParser(xContentType.xContent(), withRandomFields)) { parser.nextToken(); parser.nextToken(); - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, + XContentParseException exception = expectThrows(XContentParseException.class, () -> MeanReciprocalRank.fromXContent(parser)); - assertThat(exception.getMessage(), startsWith("[reciprocal_rank] unknown field")); + assertThat(exception.getMessage(), containsString("[reciprocal_rank] unknown field")); } } diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtKTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtKTests.java index c65ad76fdf9af..c0035d5dbb72e 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtKTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/PrecisionAtKTests.java @@ -25,6 +25,7 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; @@ -41,7 +42,7 @@ import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; import static org.elasticsearch.test.XContentTestUtils.insertRandomFields; -import static org.hamcrest.Matchers.startsWith; +import static org.hamcrest.CoreMatchers.containsString; public class PrecisionAtKTests extends ESTestCase { @@ -203,8 +204,8 @@ public void testXContentParsingIsNotLenient() throws IOException { try (XContentParser parser = createParser(xContentType.xContent(), withRandomFields)) { parser.nextToken(); parser.nextToken(); - IllegalArgumentException exception = expectThrows(IllegalArgumentException.class, () -> PrecisionAtK.fromXContent(parser)); - assertThat(exception.getMessage(), startsWith("[precision] unknown field")); + XContentParseException exception = expectThrows(XContentParseException.class, () -> PrecisionAtK.fromXContent(parser)); + assertThat(exception.getMessage(), containsString("[precision] unknown field")); } } diff --git a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentTests.java b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentTests.java index cd38233bfa9a9..c62fc1fa2bb47 100644 --- a/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentTests.java +++ b/modules/rank-eval/src/test/java/org/elasticsearch/index/rankeval/RatedDocumentTests.java @@ -24,6 +24,7 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.test.ESTestCase; @@ -33,7 +34,7 @@ import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode; import static org.elasticsearch.test.XContentTestUtils.insertRandomFields; -import static org.hamcrest.Matchers.startsWith; +import static org.hamcrest.CoreMatchers.containsString; public class RatedDocumentTests extends ESTestCase { @@ -59,8 +60,8 @@ public void testXContentParsingIsNotLenient() throws IOException { BytesReference originalBytes = toShuffledXContent(testItem, xContentType, ToXContent.EMPTY_PARAMS, randomBoolean()); BytesReference withRandomFields = insertRandomFields(xContentType, originalBytes, null, random()); try (XContentParser parser = createParser(xContentType.xContent(), withRandomFields)) { - Exception exception = expectThrows(IllegalArgumentException.class, () -> RatedDocument.fromXContent(parser)); - assertThat(exception.getMessage(), startsWith("[rated_document] unknown field")); + XContentParseException exception = expectThrows(XContentParseException.class, () -> RatedDocument.fromXContent(parser)); + assertThat(exception.getMessage(), containsString("[rated_document] unknown field")); } } diff --git a/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java b/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java index 6c9277a61bdee..c358d0fb6ca52 100644 --- a/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/admin/cluster/settings/ClusterUpdateSettingsRequestTests.java @@ -21,6 +21,7 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.xcontent.ToXContent; +import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.test.ESTestCase; @@ -29,7 +30,8 @@ import java.io.IOException; import java.util.Collections; -import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo;; public class ClusterUpdateSettingsRequestTests extends ESTestCase { @@ -51,10 +53,10 @@ private void doFromXContentTestWithRandomFields(boolean addRandomFields) throws String unsupportedField = "unsupported_field"; BytesReference mutated = BytesReference.bytes(XContentTestUtils.insertIntoXContent(xContentType.xContent(), originalBytes, Collections.singletonList(""), () -> unsupportedField, () -> randomAlphaOfLengthBetween(3, 10))); - IllegalArgumentException iae = expectThrows(IllegalArgumentException.class, + XContentParseException iae = expectThrows(XContentParseException.class, () -> ClusterUpdateSettingsRequest.fromXContent(createParser(xContentType.xContent(), mutated))); assertThat(iae.getMessage(), - equalTo("[cluster_update_settings_request] unknown field [" + unsupportedField + "], parser not found")); + containsString("[cluster_update_settings_request] unknown field [" + unsupportedField + "], parser not found")); } else { XContentParser parser = createParser(xContentType.xContent(), originalBytes); ClusterUpdateSettingsRequest parsedRequest = ClusterUpdateSettingsRequest.fromXContent(parser); diff --git a/server/src/test/java/org/elasticsearch/action/update/UpdateRequestTests.java b/server/src/test/java/org/elasticsearch/action/update/UpdateRequestTests.java index ddf4f32c2c2b4..33296bd2bd9dc 100644 --- a/server/src/test/java/org/elasticsearch/action/update/UpdateRequestTests.java +++ b/server/src/test/java/org/elasticsearch/action/update/UpdateRequestTests.java @@ -33,6 +33,7 @@ import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.common.xcontent.json.JsonXContent; @@ -71,6 +72,7 @@ public class UpdateRequestTests extends ESTestCase { private UpdateHelper updateHelper; + @Override @Before public void setUp() throws Exception { super.setUp(); @@ -290,6 +292,28 @@ public void testFieldsParsing() throws Exception { assertThat(request.fields(), arrayContaining("field1", "field2")); } + public void testUnknownFieldParsing() throws Exception { + UpdateRequest request = new UpdateRequest("test", "type", "1"); + XContentParser contentParser = createParser(XContentFactory.jsonBuilder() + .startObject() + .field("unknown_field", "test") + .endObject()); + + XContentParseException ex = expectThrows(XContentParseException.class, () -> request.fromXContent(contentParser)); + assertEquals("[1:2] [UpdateRequest] unknown field [unknown_field], parser not found", ex.getMessage()); + + UpdateRequest request2 = new UpdateRequest("test", "type", "1"); + XContentParser unknownObject = createParser(XContentFactory.jsonBuilder() + .startObject() + .field("script", "ctx.op = ctx._source.views == params.count ? 'delete' : 'none'") + .startObject("params") + .field("count", 1) + .endObject() + .endObject()); + ex = expectThrows(XContentParseException.class, () -> request2.fromXContent(unknownObject)); + assertEquals("[1:76] [UpdateRequest] unknown field [params], parser not found", ex.getMessage()); + } + public void testFetchSourceParsing() throws Exception { UpdateRequest request = new UpdateRequest("test", "type1", "1"); request.fromXContent(createParser(XContentFactory.jsonBuilder() diff --git a/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilderTests.java b/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilderTests.java index 5d06fd4cd400b..95da15e838c31 100644 --- a/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/fetch/subphase/highlight/HighlightBuilderTests.java @@ -158,10 +158,10 @@ public void testFromXContent() throws IOException { */ public void testUnknownArrayNameExpection() throws IOException { { - IllegalArgumentException e = expectParseThrows(IllegalArgumentException.class, "{\n" + + XContentParseException e = expectParseThrows(XContentParseException.class, "{\n" + " \"bad_fieldname\" : [ \"field1\" 1 \"field2\" ]\n" + "}\n"); - assertEquals("[highlight] unknown field [bad_fieldname], parser not found", e.getMessage()); + assertEquals("[2:5] [highlight] unknown field [bad_fieldname], parser not found", e.getMessage()); } { @@ -174,7 +174,7 @@ public void testUnknownArrayNameExpection() throws IOException { "}\n"); assertThat(e.getMessage(), containsString("[highlight] failed to parse field [fields]")); assertThat(e.getCause().getMessage(), containsString("[fields] failed to parse field [body]")); - assertEquals("[highlight_field] unknown field [bad_fieldname], parser not found", e.getCause().getCause().getMessage()); + assertEquals("[4:9] [highlight_field] unknown field [bad_fieldname], parser not found", e.getCause().getCause().getMessage()); } } @@ -188,10 +188,10 @@ private T expectParseThrows(Class exceptionClass, Strin */ public void testUnknownFieldnameExpection() throws IOException { { - IllegalArgumentException e = expectParseThrows(IllegalArgumentException.class, "{\n" + + XContentParseException e = expectParseThrows(XContentParseException.class, "{\n" + " \"bad_fieldname\" : \"value\"\n" + "}\n"); - assertEquals("[highlight] unknown field [bad_fieldname], parser not found", e.getMessage()); + assertEquals("[2:5] [highlight] unknown field [bad_fieldname], parser not found", e.getMessage()); } { @@ -204,7 +204,7 @@ public void testUnknownFieldnameExpection() throws IOException { "}\n"); assertThat(e.getMessage(), containsString("[highlight] failed to parse field [fields]")); assertThat(e.getCause().getMessage(), containsString("[fields] failed to parse field [body]")); - assertEquals("[highlight_field] unknown field [bad_fieldname], parser not found", e.getCause().getCause().getMessage()); + assertEquals("[4:9] [highlight_field] unknown field [bad_fieldname], parser not found", e.getCause().getCause().getMessage()); } } @@ -213,10 +213,10 @@ public void testUnknownFieldnameExpection() throws IOException { */ public void testUnknownObjectFieldnameExpection() throws IOException { { - IllegalArgumentException e = expectParseThrows(IllegalArgumentException.class, "{\n" + + XContentParseException e = expectParseThrows(XContentParseException.class, "{\n" + " \"bad_fieldname\" : { \"field\" : \"value\" }\n \n" + "}\n"); - assertEquals("[highlight] unknown field [bad_fieldname], parser not found", e.getMessage()); + assertEquals("[2:5] [highlight] unknown field [bad_fieldname], parser not found", e.getMessage()); } { @@ -229,7 +229,7 @@ public void testUnknownObjectFieldnameExpection() throws IOException { "}\n"); assertThat(e.getMessage(), containsString("[highlight] failed to parse field [fields]")); assertThat(e.getCause().getMessage(), containsString("[fields] failed to parse field [body]")); - assertEquals("[highlight_field] unknown field [bad_fieldname], parser not found", e.getCause().getCause().getMessage()); + assertEquals("[4:9] [highlight_field] unknown field [bad_fieldname], parser not found", e.getCause().getCause().getMessage()); } } diff --git a/server/src/test/java/org/elasticsearch/search/rescore/QueryRescorerBuilderTests.java b/server/src/test/java/org/elasticsearch/search/rescore/QueryRescorerBuilderTests.java index 75ac542d9853a..efd3e5ef2ca06 100644 --- a/server/src/test/java/org/elasticsearch/search/rescore/QueryRescorerBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/rescore/QueryRescorerBuilderTests.java @@ -170,6 +170,7 @@ public void testRescoreQueryNull() throws IOException { class AlwaysRewriteQueryBuilder extends MatchAllQueryBuilder { + @Override protected QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOException { return new MatchAllQueryBuilder(); } @@ -254,8 +255,8 @@ public void testUnknownFieldsExpection() throws IOException { "}\n"; { XContentParser parser = createParser(rescoreElement); - Exception e = expectThrows(IllegalArgumentException.class, () -> RescorerBuilder.parseFromXContent(parser)); - assertEquals("[query] unknown field [bad_fieldname], parser not found", e.getMessage()); + XContentParseException e = expectThrows(XContentParseException.class, () -> RescorerBuilder.parseFromXContent(parser)); + assertEquals("[3:17] [query] unknown field [bad_fieldname], parser not found", e.getMessage()); } rescoreElement = "{\n" + diff --git a/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java b/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java index 163b9391a1b98..6aceed996ccdc 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/sort/FieldSortBuilderTests.java @@ -26,6 +26,7 @@ import org.apache.lucene.search.SortedSetSelector; import org.apache.lucene.search.SortedSetSortField; import org.apache.lucene.search.TermQuery; +import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.index.fielddata.IndexFieldData.XFieldComparatorSource; @@ -309,8 +310,8 @@ public void testUnknownOptionFails() throws IOException { parser.nextToken(); parser.nextToken(); - IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> FieldSortBuilder.fromXContent(parser, "")); - assertEquals("[field_sort] unknown field [reverse], parser not found", e.getMessage()); + XContentParseException e = expectThrows(XContentParseException.class, () -> FieldSortBuilder.fromXContent(parser, "")); + assertEquals("[1:18] [field_sort] unknown field [reverse], parser not found", e.getMessage()); } @Override @@ -383,7 +384,7 @@ public QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOEx } }; sortBuilder.setNestedPath("path").setNestedFilter(rangeQuery); - FieldSortBuilder rewritten = (FieldSortBuilder) sortBuilder + FieldSortBuilder rewritten = sortBuilder .rewrite(createMockShardContext()); assertNotSame(rangeQuery, rewritten.getNestedFilter()); } @@ -400,7 +401,7 @@ public QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOEx } }; sortBuilder.setNestedSort(new NestedSortBuilder("path").setFilter(rangeQuery)); - FieldSortBuilder rewritten = (FieldSortBuilder) sortBuilder + FieldSortBuilder rewritten = sortBuilder .rewrite(createMockShardContext()); assertNotSame(rangeQuery, rewritten.getNestedSort().getFilter()); } diff --git a/server/src/test/java/org/elasticsearch/search/sort/ScriptSortBuilderTests.java b/server/src/test/java/org/elasticsearch/search/sort/ScriptSortBuilderTests.java index ed83011c26609..9a030cc3aabcb 100644 --- a/server/src/test/java/org/elasticsearch/search/sort/ScriptSortBuilderTests.java +++ b/server/src/test/java/org/elasticsearch/search/sort/ScriptSortBuilderTests.java @@ -24,7 +24,6 @@ import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.SortField; import org.apache.lucene.search.TermQuery; -import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; @@ -225,8 +224,8 @@ public void testParseBadFieldNameExceptions() throws IOException { parser.nextToken(); parser.nextToken(); - Exception e = expectThrows(IllegalArgumentException.class, () -> ScriptSortBuilder.fromXContent(parser, null)); - assertEquals("[_script] unknown field [bad_field], parser not found", e.getMessage()); + XContentParseException e = expectThrows(XContentParseException.class, () -> ScriptSortBuilder.fromXContent(parser, null)); + assertEquals("[1:15] [_script] unknown field [bad_field], parser not found", e.getMessage()); } public void testParseBadFieldNameExceptionsOnStartObject() throws IOException { @@ -237,8 +236,8 @@ public void testParseBadFieldNameExceptionsOnStartObject() throws IOException { parser.nextToken(); parser.nextToken(); - Exception e = expectThrows(IllegalArgumentException.class, () -> ScriptSortBuilder.fromXContent(parser, null)); - assertEquals("[_script] unknown field [bad_field], parser not found", e.getMessage()); + XContentParseException e = expectThrows(XContentParseException.class, () -> ScriptSortBuilder.fromXContent(parser, null)); + assertEquals("[1:15] [_script] unknown field [bad_field], parser not found", e.getMessage()); } public void testParseUnexpectedToken() throws IOException { @@ -374,7 +373,7 @@ public QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOEx } }; sortBuilder.setNestedPath("path").setNestedFilter(rangeQuery); - ScriptSortBuilder rewritten = (ScriptSortBuilder) sortBuilder + ScriptSortBuilder rewritten = sortBuilder .rewrite(createMockShardContext()); assertNotSame(rangeQuery, rewritten.getNestedFilter()); } @@ -391,7 +390,7 @@ public QueryBuilder doRewrite(QueryRewriteContext queryShardContext) throws IOEx } }; sortBuilder.setNestedSort(new NestedSortBuilder("path").setFilter(rangeQuery)); - ScriptSortBuilder rewritten = (ScriptSortBuilder) sortBuilder + ScriptSortBuilder rewritten = sortBuilder .rewrite(createMockShardContext()); assertNotSame(rangeQuery, rewritten.getNestedSort().getFilter()); } diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java index d2f3a56aebe3d..48301fa5746e2 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java @@ -132,8 +132,9 @@ protected String[] shuffleProtectedFields() { * To find the right position in the root query, we add a marker as `queryName` which * all query builders support. The added bogus field after that should trigger the exception. * Queries that allow arbitrary field names at this level need to override this test. + * @throws IOException */ - public void testUnknownField() { + public void testUnknownField() throws IOException { String marker = "#marker#"; QB testQuery; do { @@ -141,9 +142,14 @@ public void testUnknownField() { } while (testQuery.toString().contains(marker)); testQuery.queryName(marker); // to find root query to add additional bogus field there String queryAsString = testQuery.toString().replace("\"" + marker + "\"", "\"" + marker + "\", \"bogusField\" : \"someValue\""); - ParsingException e = expectThrows(ParsingException.class, () -> parseQuery(queryAsString)); - // we'd like to see the offending field name here - assertThat(e.getMessage(), containsString("bogusField")); + try { + parseQuery(queryAsString); + fail("expected ParsingException or XContentParsingException"); + } catch (ParsingException | XContentParseException e) { + // we'd like to see the offending field name here + assertThat(e.getMessage(), containsString("bogusField")); + } + } /** diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/datafeed/DatafeedConfigTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/datafeed/DatafeedConfigTests.java index a3f74d25531e4..6aa987fc0e932 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/datafeed/DatafeedConfigTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/datafeed/DatafeedConfigTests.java @@ -6,15 +6,16 @@ package org.elasticsearch.xpack.core.ml.datafeed; import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator; + import org.elasticsearch.ElasticsearchException; import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.DeprecationHandler; -import org.elasticsearch.common.xcontent.LoggingDeprecationHandler; import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.BoolQueryBuilder; @@ -155,9 +156,9 @@ protected DatafeedConfig doParseInstance(XContentParser parser) { public void testFutureConfigParse() throws IOException { XContentParser parser = XContentFactory.xContent(XContentType.JSON) .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, FUTURE_DATAFEED); - IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + XContentParseException e = expectThrows(XContentParseException.class, () -> DatafeedConfig.CONFIG_PARSER.apply(parser, null).build()); - assertEquals("[datafeed_config] unknown field [tomorrows_technology_today], parser not found", e.getMessage()); + assertEquals("[6:5] [datafeed_config] unknown field [tomorrows_technology_today], parser not found", e.getMessage()); } public void testFutureMetadataParse() throws IOException { diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/config/JobTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/config/JobTests.java index 15d1cc9300c97..521748b7ef9f8 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/config/JobTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/job/config/JobTests.java @@ -6,6 +6,7 @@ package org.elasticsearch.xpack.core.ml.job.config; import com.carrotsearch.randomizedtesting.generators.CodepointSetGenerator; + import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.Version; import org.elasticsearch.common.bytes.BytesReference; @@ -17,6 +18,7 @@ import org.elasticsearch.common.xcontent.NamedXContentRegistry; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.common.xcontent.XContentHelper; +import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.test.AbstractSerializingTestCase; @@ -78,9 +80,9 @@ protected Job doParseInstance(XContentParser parser) { public void testFutureConfigParse() throws IOException { XContentParser parser = XContentFactory.xContent(XContentType.JSON) .createParser(NamedXContentRegistry.EMPTY, DeprecationHandler.THROW_UNSUPPORTED_OPERATION, FUTURE_JOB); - IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + XContentParseException e = expectThrows(XContentParseException.class, () -> Job.CONFIG_PARSER.apply(parser, null).build()); - assertEquals("[job_details] unknown field [tomorrows_technology_today], parser not found", e.getMessage()); + assertEquals("[4:5] [job_details] unknown field [tomorrows_technology_today], parser not found", e.getMessage()); } public void testFutureMetadataParse() throws IOException { diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/output/AutodetectResultsParserTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/output/AutodetectResultsParserTests.java index d4b6f4732b352..d2356a79677c3 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/output/AutodetectResultsParserTests.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/job/process/autodetect/output/AutodetectResultsParserTests.java @@ -6,14 +6,13 @@ package org.elasticsearch.xpack.ml.job.process.autodetect.output; import org.elasticsearch.ElasticsearchParseException; -import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.core.ml.job.process.autodetect.state.Quantiles; -import org.elasticsearch.xpack.ml.job.results.AutodetectResult; import org.elasticsearch.xpack.core.ml.job.results.Bucket; import org.elasticsearch.xpack.core.ml.job.results.BucketInfluencer; +import org.elasticsearch.xpack.ml.job.results.AutodetectResult; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -389,9 +388,9 @@ public void testParse_GivenUnknownObject() throws ElasticsearchParseException, I String json = "[{\"unknown\":{\"id\": 18}}]"; InputStream inputStream = new ByteArrayInputStream(json.getBytes(StandardCharsets.UTF_8)); AutodetectResultsParser parser = new AutodetectResultsParser(Settings.EMPTY); - IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + XContentParseException e = expectThrows(XContentParseException.class, () -> parser.parseResults(inputStream).forEachRemaining(a -> {})); - assertEquals("[autodetect_result] unknown field [unknown], parser not found", e.getMessage()); + assertEquals("[1:3] [autodetect_result] unknown field [unknown], parser not found", e.getMessage()); } public void testParse_GivenArrayContainsAnotherArray() throws ElasticsearchParseException, IOException { diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/text/TextTemplateTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/text/TextTemplateTests.java index 45c34e3465096..0e084af23e1fb 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/text/TextTemplateTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/common/text/TextTemplateTests.java @@ -8,6 +8,7 @@ import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentParseException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.json.JsonXContent; import org.elasticsearch.script.Script; @@ -172,12 +173,8 @@ public void testParserInvalidUnknownScriptType() throws Exception { BytesReference bytes = BytesReference.bytes(builder); XContentParser parser = createParser(JsonXContent.jsonXContent, bytes); parser.nextToken(); - try { - TextTemplate.parse(parser); - fail("expected parse exception when script type is unknown"); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), is("[script] unknown field [template], parser not found")); - } + XContentParseException ex = expectThrows(XContentParseException.class, () -> TextTemplate.parse(parser)); + assertEquals("[1:2] [script] unknown field [template], parser not found", ex.getMessage()); } public void testParserInvalidMissingText() throws Exception { @@ -188,12 +185,8 @@ public void testParserInvalidMissingText() throws Exception { BytesReference bytes = BytesReference.bytes(builder); XContentParser parser = createParser(JsonXContent.jsonXContent, bytes); parser.nextToken(); - try { - TextTemplate.parse(parser); - fail("expected parse exception when template text is missing"); - } catch (IllegalArgumentException e) { - assertThat(e.getMessage(), containsString("[script] unknown field [type], parser not found")); - } + XContentParseException ex = expectThrows(XContentParseException.class, () -> TextTemplate.parse(parser)); + assertEquals("[1:2] [script] unknown field [type], parser not found", ex.getMessage()); } public void testNullObject() throws Exception { From 3b2b51dcef76e4842e1e8488f255f896fe23fd8b Mon Sep 17 00:00:00 2001 From: Tim Brooks Date: Mon, 4 Jun 2018 13:02:44 -0600 Subject: [PATCH 21/21] Add TRACE, CONNECT, and PATCH http methods (#31079) This is related to #31017. That issue identified that these three http methods were treated like GET requests. This commit adds them to RestRequest. This means that these methods will be handled properly and generate 405s. --- .../http/netty4/Netty4HttpRequest.java | 14 +++++++++++++- .../java/org/elasticsearch/rest/RestRequest.java | 2 +- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpRequest.java b/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpRequest.java index 5194c762b7e43..2ce6ffada67f0 100644 --- a/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpRequest.java +++ b/modules/transport-netty4/src/main/java/org/elasticsearch/http/netty4/Netty4HttpRequest.java @@ -119,7 +119,19 @@ public Method method() { return Method.OPTIONS; } - return Method.GET; + if (httpMethod == HttpMethod.PATCH) { + return Method.PATCH; + } + + if (httpMethod == HttpMethod.TRACE) { + return Method.TRACE; + } + + if (httpMethod == HttpMethod.CONNECT) { + return Method.CONNECT; + } + + throw new IllegalArgumentException("Unexpected http method: " + httpMethod); } @Override diff --git a/server/src/main/java/org/elasticsearch/rest/RestRequest.java b/server/src/main/java/org/elasticsearch/rest/RestRequest.java index bd46a20f31231..65b4f9d1d3614 100644 --- a/server/src/main/java/org/elasticsearch/rest/RestRequest.java +++ b/server/src/main/java/org/elasticsearch/rest/RestRequest.java @@ -130,7 +130,7 @@ public RestRequest( } public enum Method { - GET, POST, PUT, DELETE, OPTIONS, HEAD + GET, POST, PUT, DELETE, OPTIONS, HEAD, PATCH, TRACE, CONNECT } public abstract Method method();