From 274be7997a7e8826696ed5af5755368771ab5640 Mon Sep 17 00:00:00 2001 From: Simon Cooper Date: Fri, 21 Feb 2025 12:00:17 +0000 Subject: [PATCH 01/27] Create a SearchResponseBuilder for creating SearchResponses in tests (#122196) As well as simplifying test code, this also highlights which settings in the response are actually needed for individual tests --- .../geoip/DatabaseNodeServiceTests.java | 3 +- .../reindex/AsyncBulkByScrollActionTests.java | 18 +- .../ClientScrollableHitSourceTests.java | 18 +- ...rossClusterSearchUnavailableClusterIT.java | 22 +-- .../action/search/ExpandSearchPhaseTests.java | 18 +- .../RemoteClusterConnectionTests.java | 25 +-- .../search/SearchResponseUtils.java | 180 +++++++++++++++--- .../xpack/search/AsyncSearchTaskTests.java | 21 +- .../indexing/AsyncTwoPhaseIndexerTests.java | 42 +--- .../xpack/enrich/EnrichCacheTests.java | 48 +---- .../enrich/EnrichProcessorFactoryTests.java | 23 +-- .../xpack/enrich/action/CoordinatorTests.java | 22 +-- .../assembler/ImplicitTiebreakerTests.java | 7 +- .../assembler/SequenceSpecTests.java | 7 +- .../sequence/CircuitBreakerTests.java | 7 +- .../inference/InferenceRunnerTests.java | 43 +---- .../ResultsPersisterServiceTests.java | 30 +-- .../RollupResponseTranslationTests.java | 40 +--- .../job/RollupIndexerIndexingTests.java | 19 +- .../rollup/job/RollupIndexerStateTests.java | 103 ++-------- ...CrossClusterAccessHeadersForCcsRestIT.java | 23 +-- .../security/ScrollHelperIntegTests.java | 34 +--- ...sportSamlInvalidateSessionActionTests.java | 36 +--- .../security/authc/ApiKeyServiceTests.java | 69 +------ .../IndexServiceAccountTokenStoreTests.java | 19 +- .../mapper/NativeRoleMappingStoreTests.java | 18 +- .../store/NativePrivilegeStoreTests.java | 3 +- .../TimeBasedCheckpointProviderTests.java | 19 +- .../TransformIndexerFailureHandlingTests.java | 114 ++--------- .../TransformIndexerStateTests.java | 22 +-- .../transforms/TransformIndexerTests.java | 22 +-- .../CompositeBucketsChangeCollectorTests.java | 22 +-- .../DateHistogramFieldCollectorTests.java | 24 +-- .../transforms/pivot/PivotTests.java | 38 +--- .../CompareConditionSearchTests.java | 21 +- .../xpack/watcher/WatcherServiceTests.java | 20 +- .../execution/TriggeredWatchStoreTests.java | 19 +- 37 files changed, 297 insertions(+), 922 deletions(-) diff --git a/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/DatabaseNodeServiceTests.java b/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/DatabaseNodeServiceTests.java index 0ef4686dc033..37b406c1403c 100644 --- a/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/DatabaseNodeServiceTests.java +++ b/modules/ingest-geoip/src/test/java/org/elasticsearch/ingest/geoip/DatabaseNodeServiceTests.java @@ -50,6 +50,7 @@ import org.elasticsearch.ingest.IngestService; import org.elasticsearch.persistent.PersistentTasksCustomMetadata; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; @@ -341,7 +342,7 @@ public class DatabaseNodeServiceTests extends ESTestCase { } SearchHits hits = SearchHits.unpooled(new SearchHit[] { hit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1f); - SearchResponse searchResponse = new SearchResponse(hits, null, null, false, null, null, 0, null, 1, 1, 0, 1L, null, null); + SearchResponse searchResponse = SearchResponseUtils.successfulResponse(hits); toRelease.add(searchResponse::decRef); @SuppressWarnings("unchecked") ActionFuture actionFuture = mock(ActionFuture.class); diff --git a/modules/reindex/src/test/java/org/elasticsearch/reindex/AsyncBulkByScrollActionTests.java b/modules/reindex/src/test/java/org/elasticsearch/reindex/AsyncBulkByScrollActionTests.java index 28f2eafc20a6..db642bbdc510 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/reindex/AsyncBulkByScrollActionTests.java +++ b/modules/reindex/src/test/java/org/elasticsearch/reindex/AsyncBulkByScrollActionTests.java @@ -68,6 +68,7 @@ import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.tasks.Task; import org.elasticsearch.tasks.TaskId; import org.elasticsearch.tasks.TaskManager; @@ -574,22 +575,7 @@ public class AsyncBulkByScrollActionTests extends ESTestCase { new TotalHits(0, TotalHits.Relation.EQUAL_TO), 0 ); - SearchResponse searchResponse = new SearchResponse( - hits, - null, - null, - false, - false, - null, - 1, - scrollId(), - 5, - 4, - 0, - randomLong(), - null, - SearchResponse.Clusters.EMPTY - ); + SearchResponse searchResponse = SearchResponseUtils.response(hits).scrollId(scrollId()).shards(5, 4, 0).build(); try { client.lastSearch.get().listener.onResponse(searchResponse); diff --git a/modules/reindex/src/test/java/org/elasticsearch/reindex/ClientScrollableHitSourceTests.java b/modules/reindex/src/test/java/org/elasticsearch/reindex/ClientScrollableHitSourceTests.java index 5f4e2b3a5515..26922c62d393 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/reindex/ClientScrollableHitSourceTests.java +++ b/modules/reindex/src/test/java/org/elasticsearch/reindex/ClientScrollableHitSourceTests.java @@ -30,6 +30,7 @@ import org.elasticsearch.index.reindex.ClientScrollableHitSource; import org.elasticsearch.index.reindex.ScrollableHitSource; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.tasks.TaskId; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.TestThreadPool; @@ -166,22 +167,7 @@ public class ClientScrollableHitSourceTests extends ESTestCase { new TotalHits(0, TotalHits.Relation.EQUAL_TO), 0 ); - return new SearchResponse( - hits, - null, - null, - false, - false, - null, - 1, - randomSimpleString(random(), 1, 10), - 5, - 4, - 0, - randomLong(), - null, - SearchResponse.Clusters.EMPTY - ); + return SearchResponseUtils.response(hits).scrollId(randomSimpleString(random(), 1, 10)).shards(5, 4, 0).build(); } private void assertSameHits(List actual, SearchHit[] expected) { diff --git a/qa/ccs-unavailable-clusters/src/javaRestTest/java/org/elasticsearch/search/CrossClusterSearchUnavailableClusterIT.java b/qa/ccs-unavailable-clusters/src/javaRestTest/java/org/elasticsearch/search/CrossClusterSearchUnavailableClusterIT.java index d912ccbe0745..c80bcc79f8f6 100644 --- a/qa/ccs-unavailable-clusters/src/javaRestTest/java/org/elasticsearch/search/CrossClusterSearchUnavailableClusterIT.java +++ b/qa/ccs-unavailable-clusters/src/javaRestTest/java/org/elasticsearch/search/CrossClusterSearchUnavailableClusterIT.java @@ -12,16 +12,13 @@ package org.elasticsearch.search; import org.apache.http.HttpEntity; import org.apache.http.entity.ContentType; import org.apache.http.nio.entity.NStringEntity; -import org.apache.lucene.search.TotalHits; import org.elasticsearch.TransportVersion; import org.elasticsearch.action.admin.cluster.state.ClusterStateAction; import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest; import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; import org.elasticsearch.action.search.SearchRequest; -import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchShardsRequest; import org.elasticsearch.action.search.SearchShardsResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.search.TransportSearchAction; import org.elasticsearch.action.search.TransportSearchShardsAction; import org.elasticsearch.client.Request; @@ -33,11 +30,11 @@ import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNodes; import org.elasticsearch.cluster.node.VersionInformation; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.common.util.concurrent.ThreadContext; -import org.elasticsearch.search.aggregations.InternalAggregations; import org.elasticsearch.test.cluster.ElasticsearchCluster; import org.elasticsearch.test.rest.ESRestTestCase; import org.elasticsearch.test.rest.ObjectPath; @@ -102,21 +99,8 @@ public class CrossClusterSearchUnavailableClusterIT extends ESRestTestCase { EsExecutors.DIRECT_EXECUTOR_SERVICE, SearchRequest::new, (request, channel, task) -> { - var searchResponse = new SearchResponse( - SearchHits.empty(new TotalHits(0, TotalHits.Relation.EQUAL_TO), Float.NaN), - InternalAggregations.EMPTY, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 100, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY + var searchResponse = SearchResponseUtils.successfulResponse( + SearchHits.empty(Lucene.TOTAL_HITS_EQUAL_TO_ZERO, Float.NaN) ); try { channel.sendResponse(searchResponse); diff --git a/server/src/test/java/org/elasticsearch/action/search/ExpandSearchPhaseTests.java b/server/src/test/java/org/elasticsearch/action/search/ExpandSearchPhaseTests.java index 5f8473959951..99e695228fd3 100644 --- a/server/src/test/java/org/elasticsearch/action/search/ExpandSearchPhaseTests.java +++ b/server/src/test/java/org/elasticsearch/action/search/ExpandSearchPhaseTests.java @@ -22,6 +22,7 @@ import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.AbstractSearchTestCase; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.builder.PointInTimeBuilder; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.collapse.CollapseBuilder; @@ -173,22 +174,7 @@ public class ExpandSearchPhaseTests extends ESTestCase { @Override void sendExecuteMultiSearch(MultiSearchRequest request, SearchTask task, ActionListener listener) { assertTrue(executedMultiSearch.compareAndSet(false, true)); - SearchResponse searchResponse = new SearchResponse( - collapsedHits, - null, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ); + SearchResponse searchResponse = SearchResponseUtils.successfulResponse(collapsedHits); ActionListener.respondAndRelease( listener, new MultiSearchResponse( diff --git a/server/src/test/java/org/elasticsearch/transport/RemoteClusterConnectionTests.java b/server/src/test/java/org/elasticsearch/transport/RemoteClusterConnectionTests.java index 21346bb93ef8..a4ee85310632 100644 --- a/server/src/test/java/org/elasticsearch/transport/RemoteClusterConnectionTests.java +++ b/server/src/test/java/org/elasticsearch/transport/RemoteClusterConnectionTests.java @@ -17,10 +17,8 @@ import org.elasticsearch.action.admin.cluster.state.ClusterStateAction; import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest; import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; import org.elasticsearch.action.search.SearchRequest; -import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchShardsRequest; import org.elasticsearch.action.search.SearchShardsResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.search.TransportSearchAction; import org.elasticsearch.action.search.TransportSearchShardsAction; import org.elasticsearch.action.support.PlainActionFuture; @@ -46,7 +44,7 @@ import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.mocksocket.MockServerSocket; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; -import org.elasticsearch.search.aggregations.InternalAggregations; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.transport.MockTransportService; import org.elasticsearch.threadpool.TestThreadPool; @@ -157,26 +155,7 @@ public class RemoteClusterConnectionTests extends ESTestCase { } else { searchHits = SearchHits.empty(new TotalHits(0, TotalHits.Relation.EQUAL_TO), Float.NaN); } - try ( - var searchResponseRef = ReleasableRef.of( - new SearchResponse( - searchHits, - InternalAggregations.EMPTY, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 100, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ) - ) - ) { + try (var searchResponseRef = ReleasableRef.of(SearchResponseUtils.successfulResponse(searchHits))) { channel.sendResponse(searchResponseRef.get()); } } diff --git a/test/framework/src/main/java/org/elasticsearch/search/SearchResponseUtils.java b/test/framework/src/main/java/org/elasticsearch/search/SearchResponseUtils.java index 21b43636222f..032155073666 100644 --- a/test/framework/src/main/java/org/elasticsearch/search/SearchResponseUtils.java +++ b/test/framework/src/main/java/org/elasticsearch/search/SearchResponseUtils.java @@ -15,6 +15,7 @@ import org.elasticsearch.ElasticsearchException; import org.elasticsearch.action.search.MultiSearchResponse; import org.elasticsearch.action.search.SearchRequestBuilder; import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.action.search.SearchResponse.Clusters; import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.client.Response; import org.elasticsearch.cluster.metadata.IndexMetadata; @@ -22,6 +23,7 @@ import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.document.DocumentField; +import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.text.Text; import org.elasticsearch.common.util.concurrent.ConcurrentCollections; import org.elasticsearch.common.xcontent.XContentParserUtils; @@ -76,6 +78,157 @@ import static org.elasticsearch.xcontent.ConstructingObjectParser.optionalConstr public enum SearchResponseUtils { ; + public static SearchResponseBuilder response() { + return new SearchResponseBuilder(); + } + + public static SearchResponseBuilder response(SearchHits hits) { + return new SearchResponseBuilder().searchHits(hits).numReducePhases(1).shards(1, 1, 0).tookInMillis(100); + } + + public static SearchResponse successfulResponse(SearchHits hits) { + return response(hits).build(); + } + + public static SearchResponse emptyWithTotalHits( + String scrollId, + int totalShards, + int successfulShards, + int skippedShards, + long tookInMillis, + ShardSearchFailure[] shardFailures, + SearchResponse.Clusters clusters + ) { + return new SearchResponse( + SearchHits.EMPTY_WITH_TOTAL_HITS, + null, + null, + false, + null, + null, + 1, + scrollId, + totalShards, + successfulShards, + skippedShards, + tookInMillis, + shardFailures, + clusters + ); + } + + public static class SearchResponseBuilder { + private SearchHits searchHits = SearchHits.empty(Lucene.TOTAL_HITS_EQUAL_TO_ZERO, Float.NaN); + private InternalAggregations aggregations; + private Suggest suggest; + private boolean timedOut; + private Boolean terminatedEarly; + private SearchProfileResults profileResults; + private int numReducePhases; + private String scrollId; + private int totalShards; + private int successfulShards; + private int skippedShards; + private long tookInMillis; + private List shardFailures; + private Clusters clusters = Clusters.EMPTY; + private BytesReference pointInTimeId; + + private SearchResponseBuilder() {} + + public SearchResponseBuilder searchHits(SearchHits searchHits) { + this.searchHits = searchHits; + return this; + } + + public SearchResponseBuilder aggregations(InternalAggregations aggregations) { + this.aggregations = aggregations; + return this; + } + + public SearchResponseBuilder suggest(Suggest suggest) { + this.suggest = suggest; + return this; + } + + public SearchResponseBuilder timedOut(boolean timedOut) { + this.timedOut = timedOut; + return this; + } + + public SearchResponseBuilder terminatedEarly(Boolean terminatedEarly) { + this.terminatedEarly = terminatedEarly; + return this; + } + + public SearchResponseBuilder profileResults(SearchProfileResults profileResults) { + this.profileResults = profileResults; + return this; + } + + public SearchResponseBuilder numReducePhases(int numReducePhases) { + this.numReducePhases = numReducePhases; + return this; + } + + public SearchResponseBuilder scrollId(String scrollId) { + this.scrollId = scrollId; + return this; + } + + public SearchResponseBuilder shards(int total, int successful, int skipped) { + this.totalShards = total; + this.successfulShards = successful; + this.skippedShards = skipped; + return this; + } + + public SearchResponseBuilder tookInMillis(long tookInMillis) { + this.tookInMillis = tookInMillis; + return this; + } + + public SearchResponseBuilder shardFailures(ShardSearchFailure... failures) { + shardFailures = List.of(failures); + return this; + } + + public SearchResponseBuilder shardFailures(List failures) { + shardFailures = List.copyOf(failures); + return this; + } + + public SearchResponseBuilder clusters(Clusters clusters) { + this.clusters = clusters; + return this; + } + + public SearchResponseBuilder pointInTimeId(BytesReference pointInTimeId) { + this.pointInTimeId = pointInTimeId; + return this; + } + + public SearchResponse build() { + return new SearchResponse( + searchHits, + aggregations, + suggest, + timedOut, + terminatedEarly, + profileResults, + numReducePhases, + scrollId, + totalShards, + successfulShards, + skippedShards, + tookInMillis, + shardFailures == null ? ShardSearchFailure.EMPTY_ARRAY : shardFailures.toArray(ShardSearchFailure[]::new), + clusters, + pointInTimeId + ); + } + } + // All fields on the root level of the parsed SearchHit are interpreted as metadata fields // public because we use it in a completion suggestion option @SuppressWarnings("unchecked") @@ -110,33 +263,6 @@ public enum SearchResponseUtils { } } - public static SearchResponse emptyWithTotalHits( - String scrollId, - int totalShards, - int successfulShards, - int skippedShards, - long tookInMillis, - ShardSearchFailure[] shardFailures, - SearchResponse.Clusters clusters - ) { - return new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - null, - null, - false, - null, - null, - 1, - scrollId, - totalShards, - successfulShards, - skippedShards, - tookInMillis, - shardFailures, - clusters - ); - } - public static SearchResponse parseSearchResponse(XContentParser parser) throws IOException { ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser); parser.nextToken(); diff --git a/x-pack/plugin/async-search/src/test/java/org/elasticsearch/xpack/search/AsyncSearchTaskTests.java b/x-pack/plugin/async-search/src/test/java/org/elasticsearch/xpack/search/AsyncSearchTaskTests.java index cf08cdbf0936..ab1b6189c013 100644 --- a/x-pack/plugin/async-search/src/test/java/org/elasticsearch/xpack/search/AsyncSearchTaskTests.java +++ b/x-pack/plugin/async-search/src/test/java/org/elasticsearch/xpack/search/AsyncSearchTaskTests.java @@ -23,6 +23,7 @@ import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.SearchShardTarget; import org.elasticsearch.search.aggregations.BucketOrder; import org.elasticsearch.search.aggregations.InternalAggregations; @@ -472,22 +473,10 @@ public class AsyncSearchTaskTests extends ESTestCase { int skippedShards, ShardSearchFailure... failures ) { - return new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - InternalAggregations.EMPTY, - null, - false, - null, - null, - 1, - null, - totalShards, - successfulShards, - skippedShards, - 100, - failures, - SearchResponse.Clusters.EMPTY - ); + return SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS) + .shards(totalShards, successfulShards, skippedShards) + .shardFailures(failures) + .build(); } private static void assertCompletionListeners( diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexing/AsyncTwoPhaseIndexerTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexing/AsyncTwoPhaseIndexerTests.java index 76b668a87cff..6f0c5fba2cf5 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexing/AsyncTwoPhaseIndexerTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/indexing/AsyncTwoPhaseIndexerTests.java @@ -13,10 +13,10 @@ import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.TimeValue; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ExecutorBuilder; import org.elasticsearch.threadpool.TestThreadPool; @@ -113,25 +113,7 @@ public class AsyncTwoPhaseIndexerTests extends ESTestCase { return; } - ActionListener.respondAndRelease( - nextPhase, - new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - null, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - null - ) - ); + ActionListener.respondAndRelease(nextPhase, SearchResponseUtils.successfulResponse(SearchHits.EMPTY_WITH_TOTAL_HITS)); } @Override @@ -264,25 +246,7 @@ public class AsyncTwoPhaseIndexerTests extends ESTestCase { awaitForLatch(); } - ActionListener.respondAndRelease( - nextPhase, - new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - null, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - null - ) - ); + ActionListener.respondAndRelease(nextPhase, SearchResponseUtils.successfulResponse(SearchHits.EMPTY_WITH_TOTAL_HITS)); } @Override diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichCacheTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichCacheTests.java index 7125dfd45eaf..693d4cb55bca 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichCacheTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichCacheTests.java @@ -6,12 +6,12 @@ */ package org.elasticsearch.xpack.enrich; -import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.core.TimeValue; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.json.JsonXContent; @@ -26,6 +26,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import static org.elasticsearch.action.support.ActionTestUtils.assertNoFailureListener; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.notNullValue; @@ -122,18 +123,10 @@ public class EnrichCacheTests extends ESTestCase { searchResponseActionListener.onResponse(searchResponse); searchResponse.decRef(); queriedDatabaseLatch.countDown(); - }, new ActionListener<>() { - @Override - public void onResponse(List> response) { - assertThat(response, equalTo(searchResponseMap)); - notifiedOfResultLatch.countDown(); - } - - @Override - public void onFailure(Exception e) { - fail(e); - } - }); + }, assertNoFailureListener(response -> { + assertThat(response, equalTo(searchResponseMap)); + notifiedOfResultLatch.countDown(); + })); assertThat(queriedDatabaseLatch.await(5, TimeUnit.SECONDS), equalTo(true)); assertThat(notifiedOfResultLatch.await(5, TimeUnit.SECONDS), equalTo(true)); EnrichStatsAction.Response.CacheStats cacheStats = enrichCache.getStats(randomAlphaOfLength(10)); @@ -149,17 +142,7 @@ public class EnrichCacheTests extends ESTestCase { CountDownLatch notifiedOfResultLatch = new CountDownLatch(1); enrichCache.computeIfAbsent("policy1-1", "1", 1, (searchResponseActionListener) -> { fail("Expected no call to the database because item should have been in the cache"); - }, new ActionListener<>() { - @Override - public void onResponse(List> maps) { - notifiedOfResultLatch.countDown(); - } - - @Override - public void onFailure(Exception e) { - fail(e); - } - }); + }, assertNoFailureListener(r -> notifiedOfResultLatch.countDown())); assertThat(notifiedOfResultLatch.await(5, TimeUnit.SECONDS), equalTo(true)); EnrichStatsAction.Response.CacheStats cacheStats = enrichCache.getStats(randomAlphaOfLength(10)); assertThat(cacheStats.count(), equalTo(1L)); @@ -180,22 +163,7 @@ public class EnrichCacheTests extends ESTestCase { } }).toArray(SearchHit[]::new); SearchHits hits = SearchHits.unpooled(hitArray, null, 0); - return new SearchResponse( - hits, - null, - null, - false, - false, - null, - 1, - null, - 5, - 4, - 0, - randomLong(), - null, - SearchResponse.Clusters.EMPTY - ); + return SearchResponseUtils.response(hits).shards(5, 4, 0).build(); } private BytesReference convertMapToJson(Map simpleMap) throws IOException { diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichProcessorFactoryTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichProcessorFactoryTests.java index f10c8e4e41c9..67c88a024e74 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichProcessorFactoryTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/EnrichProcessorFactoryTests.java @@ -11,8 +11,6 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRequest; import org.elasticsearch.action.ActionResponse; import org.elasticsearch.action.ActionType; -import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.metadata.AliasMetadata; @@ -25,9 +23,7 @@ import org.elasticsearch.index.VersionType; import org.elasticsearch.ingest.IngestDocument; import org.elasticsearch.script.ScriptService; import org.elasticsearch.search.SearchHits; -import org.elasticsearch.search.aggregations.InternalAggregations; -import org.elasticsearch.search.profile.SearchProfileResults; -import org.elasticsearch.search.suggest.Suggest; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.client.NoOpClient; import org.elasticsearch.xpack.core.enrich.EnrichPolicy; @@ -257,22 +253,7 @@ public class EnrichProcessorFactoryTests extends ESTestCase { requestCounter[0]++; ActionListener.respondAndRelease( listener, - (Response) new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - InternalAggregations.EMPTY, - new Suggest(Collections.emptyList()), - false, - false, - new SearchProfileResults(Collections.emptyMap()), - 1, - "", - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ) + (Response) SearchResponseUtils.successfulResponse(SearchHits.EMPTY_WITH_TOTAL_HITS) ); } }; diff --git a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/CoordinatorTests.java b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/CoordinatorTests.java index db523546e13b..d9b2237bdf4c 100644 --- a/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/CoordinatorTests.java +++ b/x-pack/plugin/enrich/src/test/java/org/elasticsearch/xpack/enrich/action/CoordinatorTests.java @@ -7,7 +7,6 @@ package org.elasticsearch.xpack.enrich.action; import org.apache.logging.log4j.util.BiConsumer; -import org.apache.lucene.search.TotalHits; import org.elasticsearch.action.ActionFuture; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.ActionRequest; @@ -17,13 +16,13 @@ import org.elasticsearch.action.search.MultiSearchRequest; import org.elasticsearch.action.search.MultiSearchResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.support.single.shard.SingleShardRequest; import org.elasticsearch.client.internal.ElasticsearchClient; +import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.core.Tuple; import org.elasticsearch.index.query.MatchQueryBuilder; import org.elasticsearch.search.SearchHits; -import org.elasticsearch.search.aggregations.InternalAggregations; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.TestThreadPool; import org.elasticsearch.threadpool.ThreadPool; @@ -371,22 +370,7 @@ public class CoordinatorTests extends ESTestCase { } private static SearchResponse emptySearchResponse() { - return new SearchResponse( - SearchHits.empty(new TotalHits(0, TotalHits.Relation.EQUAL_TO), Float.NaN), - InternalAggregations.EMPTY, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 100, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ); + return SearchResponseUtils.successfulResponse(SearchHits.empty(Lucene.TOTAL_HITS_EQUAL_TO_ZERO, Float.NaN)); } private class MockLookupFunction implements BiConsumer> { diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/assembler/ImplicitTiebreakerTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/assembler/ImplicitTiebreakerTests.java index abd928b04a9c..e8046114ae50 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/assembler/ImplicitTiebreakerTests.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/assembler/ImplicitTiebreakerTests.java @@ -12,12 +12,12 @@ import org.apache.lucene.search.TotalHits.Relation; import org.elasticsearch.ExceptionsHelper; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.SearchResponse.Clusters; import org.elasticsearch.common.breaker.NoopCircuitBreaker; import org.elasticsearch.core.TimeValue; import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.SearchSortValues; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.test.ESTestCase; @@ -82,10 +82,7 @@ public class ImplicitTiebreakerTests extends ESTestCase { ) ); SearchHits searchHits = SearchHits.unpooled(new SearchHit[] { searchHit }, new TotalHits(1, Relation.EQUAL_TO), 0.0f); - ActionListener.respondAndRelease( - l, - new SearchResponse(searchHits, null, null, false, false, null, 0, null, 0, 1, 0, 0, null, Clusters.EMPTY) - ); + ActionListener.respondAndRelease(l, SearchResponseUtils.successfulResponse(searchHits)); } @Override diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/assembler/SequenceSpecTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/assembler/SequenceSpecTests.java index f6aa851b2fff..d07de96f09e5 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/assembler/SequenceSpecTests.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/assembler/SequenceSpecTests.java @@ -13,7 +13,6 @@ import org.apache.lucene.search.TotalHits; import org.apache.lucene.search.TotalHits.Relation; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.SearchResponse.Clusters; import org.elasticsearch.action.support.ActionTestUtils; import org.elasticsearch.common.breaker.NoopCircuitBreaker; import org.elasticsearch.common.document.DocumentField; @@ -22,6 +21,7 @@ import org.elasticsearch.core.TimeValue; import org.elasticsearch.core.Tuple; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xpack.eql.action.EqlSearchResponse.Sequence; @@ -220,10 +220,7 @@ public class SequenceSpecTests extends ESTestCase { new TotalHits(eah.hits.size(), Relation.EQUAL_TO), 0.0f ); - ActionListener.respondAndRelease( - l, - new SearchResponse(searchHits, null, null, false, false, null, 0, null, 0, 1, 0, 0, null, Clusters.EMPTY) - ); + ActionListener.respondAndRelease(l, SearchResponseUtils.successfulResponse(searchHits)); } @Override diff --git a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/sequence/CircuitBreakerTests.java b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/sequence/CircuitBreakerTests.java index 58448d981fcc..ef4402f9e941 100644 --- a/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/sequence/CircuitBreakerTests.java +++ b/x-pack/plugin/eql/src/test/java/org/elasticsearch/xpack/eql/execution/sequence/CircuitBreakerTests.java @@ -20,7 +20,6 @@ import org.elasticsearch.action.search.OpenPointInTimeResponse; import org.elasticsearch.action.search.SearchPhaseExecutionException; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.SearchResponse.Clusters; import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.support.ActionTestUtils; import org.elasticsearch.common.ParsingException; @@ -44,6 +43,7 @@ import org.elasticsearch.indices.breaker.HierarchyCircuitBreakerService; import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.SearchShardTarget; import org.elasticsearch.search.SearchSortValues; import org.elasticsearch.search.builder.SearchSourceBuilder; @@ -114,10 +114,7 @@ public class CircuitBreakerTests extends ESTestCase { new SearchSortValues(new Long[] { (long) ordinal, 1L }, new DocValueFormat[] { DocValueFormat.RAW, DocValueFormat.RAW }) ); SearchHits searchHits = SearchHits.unpooled(new SearchHit[] { searchHit }, new TotalHits(1, Relation.EQUAL_TO), 0.0f); - ActionListener.respondAndRelease( - l, - new SearchResponse(searchHits, null, null, false, false, null, 0, null, 0, 1, 0, 0, null, Clusters.EMPTY) - ); + ActionListener.respondAndRelease(l, SearchResponseUtils.successfulResponse(searchHits)); } @Override diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/dataframe/inference/InferenceRunnerTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/dataframe/inference/InferenceRunnerTests.java index c86596f23722..6e98f4814218 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/dataframe/inference/InferenceRunnerTests.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/dataframe/inference/InferenceRunnerTests.java @@ -15,7 +15,6 @@ import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.client.internal.Client; import org.elasticsearch.common.bytes.BytesReference; @@ -29,8 +28,6 @@ import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.aggregations.InternalAggregations; import org.elasticsearch.search.aggregations.metrics.Max; -import org.elasticsearch.search.profile.SearchProfileResults; -import org.elasticsearch.search.suggest.Suggest; import org.elasticsearch.tasks.TaskId; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; @@ -57,7 +54,6 @@ import org.mockito.Mockito; import java.io.IOException; import java.util.ArrayDeque; -import java.util.ArrayList; import java.util.Deque; import java.util.List; import java.util.Map; @@ -253,39 +249,12 @@ public class InferenceRunnerTests extends ESTestCase { when(threadpool.getThreadContext()).thenReturn(new ThreadContext(Settings.EMPTY)); when(client.threadPool()).thenReturn(threadpool); - Supplier withHits = () -> new SearchResponse( - SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f), - InternalAggregations.from(List.of(new Max(DestinationIndex.INCREMENTAL_ID, 1, DocValueFormat.RAW, Map.of()))), - new Suggest(new ArrayList<>()), - false, - false, - new SearchProfileResults(Map.of()), - 1, - "", - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ); - Supplier withNoHits = () -> new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - // Simulate completely null aggs - null, - new Suggest(new ArrayList<>()), - false, - false, - new SearchProfileResults(Map.of()), - 1, - "", - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ); + Supplier withHits = () -> SearchResponseUtils.response( + SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f) + ) + .aggregations(InternalAggregations.from(List.of(new Max(DestinationIndex.INCREMENTAL_ID, 1, DocValueFormat.RAW, Map.of())))) + .build(); + Supplier withNoHits = () -> SearchResponseUtils.successfulResponse(SearchHits.EMPTY_WITH_TOTAL_HITS); when(client.search(any())).thenReturn(response(withHits)).thenReturn(response(withNoHits)); return client; diff --git a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/utils/persistence/ResultsPersisterServiceTests.java b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/utils/persistence/ResultsPersisterServiceTests.java index 7a513f12bf30..8115c0f8e42a 100644 --- a/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/utils/persistence/ResultsPersisterServiceTests.java +++ b/x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/utils/persistence/ResultsPersisterServiceTests.java @@ -18,7 +18,6 @@ import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.search.TransportSearchAction; import org.elasticsearch.client.internal.Client; import org.elasticsearch.client.internal.OriginSettingClient; @@ -79,31 +78,10 @@ public class ResultsPersisterServiceTests extends ESTestCase { // Constants for searchWithRetry tests private static final SearchRequest SEARCH_REQUEST = new SearchRequest("my-index"); - public static final SearchResponse SEARCH_RESPONSE_SUCCESS = SearchResponseUtils.emptyWithTotalHits( - null, - 1, - 1, - 0, - 1L, - ShardSearchFailure.EMPTY_ARRAY, - null - ); - public static final SearchResponse SEARCH_RESPONSE_FAILURE = new SearchResponse( - SearchHits.EMPTY_WITHOUT_TOTAL_HITS, - null, - null, - false, - null, - null, - 1, - null, - 1, - 0, - 0, - 1L, - ShardSearchFailure.EMPTY_ARRAY, - null - ); + public static final SearchResponse SEARCH_RESPONSE_SUCCESS = SearchResponseUtils.successfulResponse(SearchHits.EMPTY_WITH_TOTAL_HITS); + public static final SearchResponse SEARCH_RESPONSE_FAILURE = SearchResponseUtils.response(SearchHits.EMPTY_WITHOUT_TOTAL_HITS) + .shards(1, 0, 0) + .build(); // Constants for bulkIndexWithRetry tests private static final IndexRequest INDEX_REQUEST_SUCCESS = new IndexRequest("my-index").id("success") diff --git a/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/RollupResponseTranslationTests.java b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/RollupResponseTranslationTests.java index 399e33c1871e..88abbd9d8924 100644 --- a/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/RollupResponseTranslationTests.java +++ b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/RollupResponseTranslationTests.java @@ -44,6 +44,7 @@ import org.elasticsearch.indices.breaker.NoneCircuitBreakerService; import org.elasticsearch.script.ScriptService; import org.elasticsearch.search.DocValueFormat; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.aggregations.AggregationBuilder; import org.elasticsearch.search.aggregations.AggregationReduceContext; import org.elasticsearch.search.aggregations.Aggregator; @@ -561,43 +562,16 @@ public class RollupResponseTranslationTests extends AggregatorTestCase { iw.addDocument(singleton(new NumericDocValuesField("number", 3))); }, filterBuilder, new MappedFieldType[] { fieldType }, new MappedFieldType[] { fieldType }); - // TODO SearchResponse.Clusters is not public, using null for now. Should fix upstream. MultiSearchResponse.Item unrolledItem = new MultiSearchResponse.Item( - new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - InternalAggregations.from(Collections.singletonList(responses.get(0))), - null, - false, - false, - null, - 1, - null, - 1, - 1, - 0, - 10, - null, - null - ), + SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS) + .aggregations(InternalAggregations.from(responses.get(0))) + .build(), null ); MultiSearchResponse.Item rolledItem = new MultiSearchResponse.Item( - new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - InternalAggregations.from(Collections.singletonList(responses.get(1))), - null, - false, - false, - null, - 1, - null, - 1, - 1, - 0, - 10, - null, - null - ), + SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS) + .aggregations(InternalAggregations.from(responses.get(1))) + .build(), null ); diff --git a/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/job/RollupIndexerIndexingTests.java b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/job/RollupIndexerIndexingTests.java index 34f1f2f97a32..76f81801135f 100644 --- a/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/job/RollupIndexerIndexingTests.java +++ b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/job/RollupIndexerIndexingTests.java @@ -27,7 +27,6 @@ import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.common.Rounding; import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.core.TimeValue; @@ -44,6 +43,7 @@ import org.elasticsearch.index.query.SearchExecutionContext; import org.elasticsearch.index.query.SearchExecutionContextHelper; import org.elasticsearch.script.ScriptCompiler; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.aggregations.AggregatorTestCase; import org.elasticsearch.search.aggregations.InternalAggregations; import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder; @@ -868,22 +868,7 @@ public class RollupIndexerIndexingTests extends AggregatorTestCase { } ActionListener.respondAndRelease( listener, - new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - InternalAggregations.from(Collections.singletonList(result)), - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - null - ) + SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS).aggregations(InternalAggregations.from(result)).build() ); } diff --git a/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/job/RollupIndexerStateTests.java b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/job/RollupIndexerStateTests.java index ad5e6a0cf9b4..40b6741f09ba 100644 --- a/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/job/RollupIndexerStateTests.java +++ b/x-pack/plugin/rollup/src/test/java/org/elasticsearch/xpack/rollup/job/RollupIndexerStateTests.java @@ -15,6 +15,7 @@ import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.aggregations.InternalAggregations; import org.elasticsearch.search.aggregations.bucket.composite.InternalComposite; import org.elasticsearch.test.ESTestCase; @@ -75,26 +76,9 @@ public class RollupIndexerStateTests extends ESTestCase { when(composite.getBuckets()).thenReturn(List.of()); when(composite.getName()).thenReturn(AGGREGATION_NAME); - InternalAggregations aggs = InternalAggregations.from(List.of(composite)); - ActionListener.respondAndRelease( nextPhase, - new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - aggs, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 0, - new ShardSearchFailure[0], - null - ) + SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS).aggregations(InternalAggregations.from(composite)).build() ); } @@ -426,26 +410,11 @@ public class RollupIndexerStateTests extends ESTestCase { }); when(composite.getName()).thenReturn(AGGREGATION_NAME); - InternalAggregations aggs = InternalAggregations.from(List.of(composite)); - ActionListener.respondAndRelease( nextPhase, - new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - aggs, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - null - ) + SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS) + .aggregations(InternalAggregations.from(composite)) + .build() ); } @@ -595,24 +564,9 @@ public class RollupIndexerStateTests extends ESTestCase { when(composite.getBuckets()).thenReturn(List.of(bucket)); when(composite.getName()).thenReturn(RollupField.NAME); - InternalAggregations aggs = InternalAggregations.from(List.of(composite)); - - return new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - aggs, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - null - ); + return SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS) + .aggregations(InternalAggregations.from(composite)) + .build(); }; Function bulkFunction = bulkRequest -> new BulkResponse(new BulkItemResponse[0], 100); @@ -681,23 +635,9 @@ public class RollupIndexerStateTests extends ESTestCase { when(composite.getBuckets()).thenReturn(List.of(bucket)); when(composite.getName()).thenReturn(RollupField.NAME); - InternalAggregations aggs = InternalAggregations.from(List.of(composite)); - return new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - aggs, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - null - ); + return SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS) + .aggregations(InternalAggregations.from(composite)) + .build(); }; Function bulkFunction = bulkRequest -> new BulkResponse(new BulkItemResponse[0], 100); @@ -813,24 +753,9 @@ public class RollupIndexerStateTests extends ESTestCase { when(composite.getName()).thenReturn(RollupField.NAME); when(composite.getBuckets()).thenReturn(List.of(bucket)); - InternalAggregations aggs = InternalAggregations.from(List.of(composite)); - - return new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - aggs, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - null - ); + return SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS) + .aggregations(InternalAggregations.from(composite)) + .build(); }; Function bulkFunction = bulkRequest -> { diff --git a/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/crossclusteraccess/CrossClusterAccessHeadersForCcsRestIT.java b/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/crossclusteraccess/CrossClusterAccessHeadersForCcsRestIT.java index 500b796e6266..df3392cfe9e1 100644 --- a/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/crossclusteraccess/CrossClusterAccessHeadersForCcsRestIT.java +++ b/x-pack/plugin/security/qa/security-trial/src/javaRestTest/java/org/elasticsearch/xpack/security/crossclusteraccess/CrossClusterAccessHeadersForCcsRestIT.java @@ -10,17 +10,14 @@ package org.elasticsearch.xpack.security.crossclusteraccess; import org.apache.http.HttpEntity; import org.apache.http.entity.ContentType; import org.apache.http.nio.entity.NStringEntity; -import org.apache.lucene.search.TotalHits; import org.elasticsearch.TransportVersion; import org.elasticsearch.action.admin.cluster.remote.RemoteClusterNodesAction; import org.elasticsearch.action.admin.cluster.state.ClusterStateAction; import org.elasticsearch.action.admin.cluster.state.ClusterStateRequest; import org.elasticsearch.action.admin.cluster.state.ClusterStateResponse; import org.elasticsearch.action.search.SearchRequest; -import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchShardsRequest; import org.elasticsearch.action.search.SearchShardsResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.search.TransportSearchAction; import org.elasticsearch.action.search.TransportSearchShardsAction; import org.elasticsearch.client.Request; @@ -29,6 +26,7 @@ import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.node.VersionInformation; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.lucene.Lucene; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.transport.TransportAddress; @@ -37,7 +35,7 @@ import org.elasticsearch.common.util.concurrent.EsExecutors; import org.elasticsearch.core.ReleasableRef; import org.elasticsearch.core.Tuple; import org.elasticsearch.search.SearchHits; -import org.elasticsearch.search.aggregations.InternalAggregations; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.rest.ObjectPath; import org.elasticsearch.test.transport.MockTransportService; @@ -1218,22 +1216,7 @@ public class CrossClusterAccessHeadersForCcsRestIT extends SecurityOnTrialLicens ); try ( var searchResponseRef = ReleasableRef.of( - new SearchResponse( - SearchHits.empty(new TotalHits(0, TotalHits.Relation.EQUAL_TO), Float.NaN), - InternalAggregations.EMPTY, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 100, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ) + SearchResponseUtils.successfulResponse(SearchHits.empty(Lucene.TOTAL_HITS_EQUAL_TO_ZERO, Float.NaN)) ) ) { channel.sendResponse(searchResponseRef.get()); diff --git a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/ScrollHelperIntegTests.java b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/ScrollHelperIntegTests.java index 79cf0cb9f798..655143f1cb16 100644 --- a/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/ScrollHelperIntegTests.java +++ b/x-pack/plugin/security/src/internalClusterTest/java/org/elasticsearch/xpack/security/ScrollHelperIntegTests.java @@ -11,7 +11,6 @@ import org.apache.lucene.util.CollectionUtil; import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.client.internal.Client; import org.elasticsearch.common.settings.Settings; @@ -20,6 +19,7 @@ import org.elasticsearch.core.TimeValue; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESSingleNodeTestCase; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.core.security.ScrollHelper; @@ -32,6 +32,7 @@ import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import static org.elasticsearch.action.support.ActionTestUtils.assertNoSuccessListener; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; @@ -87,26 +88,13 @@ public class ScrollHelperIntegTests extends ESSingleNodeTestCase { ActionListener listener = (ActionListener) invocation.getArguments()[1]; ActionListener.respondAndRelease( listener, - new SearchResponse( + SearchResponseUtils.response( SearchHits.unpooled( new SearchHit[] { SearchHit.unpooled(1), SearchHit.unpooled(2) }, new TotalHits(3, TotalHits.Relation.EQUAL_TO), 1 - ), - null, - null, - false, - false, - null, - 1, - scrollId, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ) + ) + ).scrollId(scrollId).build() ); return null; }; @@ -117,17 +105,7 @@ public class ScrollHelperIntegTests extends ESSingleNodeTestCase { doAnswer(returnResponse).when(client).searchScroll(any(), any()); AtomicReference failure = new AtomicReference<>(); - ScrollHelper.fetchAllByEntity(client, request, new ActionListener>() { - @Override - public void onResponse(Collection response) { - fail("This shouldn't succeed."); - } - - @Override - public void onFailure(Exception e) { - failure.set(e); - } - }, Function.identity()); + ScrollHelper.fetchAllByEntity(client, request, assertNoSuccessListener(failure::set), Function.identity()); assertNotNull("onFailure wasn't called", failure.get()); assertEquals( diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java index 269f8cb0471f..5dc71de2f4db 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/action/saml/TransportSamlInvalidateSessionActionTests.java @@ -26,7 +26,6 @@ import org.elasticsearch.action.index.TransportIndexAction; import org.elasticsearch.action.search.ClearScrollRequest; import org.elasticsearch.action.search.ClearScrollResponse; import org.elasticsearch.action.search.SearchRequest; -import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.search.SearchScrollRequest; import org.elasticsearch.action.search.TransportClearScrollAction; import org.elasticsearch.action.search.TransportSearchAction; @@ -53,6 +52,7 @@ import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.license.MockLicenseState; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.tasks.Task; import org.elasticsearch.test.ClusterServiceUtils; import org.elasticsearch.test.client.NoOpClient; @@ -203,22 +203,7 @@ public class TransportSamlInvalidateSessionActionTests extends SamlTestCase { try { ActionListener.respondAndRelease( listener, - (Response) new SearchResponse( - searchHits, - null, - null, - false, - false, - null, - 1, - "_scrollId1", - 1, - 1, - 0, - 1, - null, - null - ) + (Response) SearchResponseUtils.response(searchHits).scrollId("_scrollId1").build() ); } finally { searchHits.decRef(); @@ -227,22 +212,7 @@ public class TransportSamlInvalidateSessionActionTests extends SamlTestCase { assertThat(request, instanceOf(SearchScrollRequest.class)); ActionListener.respondAndRelease( listener, - (Response) new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - null, - null, - false, - false, - null, - 1, - "_scrollId1", - 1, - 1, - 0, - 1, - null, - null - ) + (Response) SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS).scrollId("_scrollId1").build() ); } else if (TransportClearScrollAction.NAME.equals(action.name())) { assertThat(request, instanceOf(ClearScrollRequest.class)); diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java index c7632943b63b..7d06f90ca95d 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/ApiKeyServiceTests.java @@ -62,6 +62,7 @@ import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.telemetry.Measurement; import org.elasticsearch.telemetry.TestTelemetryPlugin; import org.elasticsearch.telemetry.metric.MeterRegistry; @@ -478,7 +479,7 @@ public class ApiKeyServiceTests extends ESTestCase { builder.map(apiKeySourceDoc); searchHits[1].sourceRef(BytesReference.bytes(builder)); } - return new SearchResponse( + return SearchResponseUtils.successfulResponse( SearchHits.unpooled( searchHits, new TotalHits(searchHits.length, TotalHits.Relation.EQUAL_TO), @@ -486,20 +487,7 @@ public class ApiKeyServiceTests extends ESTestCase { null, null, null - ), - null, - null, - false, - null, - null, - 0, - randomAlphaOfLengthBetween(3, 8), - 1, - 1, - 0, - 10, - null, - null + ) ); }; doAnswer(invocation -> { @@ -637,7 +625,7 @@ public class ApiKeyServiceTests extends ESTestCase { } ActionListener.respondAndRelease( listener, - new SearchResponse( + SearchResponseUtils.successfulResponse( SearchHits.unpooled( new SearchHit[] { searchHit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), @@ -645,20 +633,7 @@ public class ApiKeyServiceTests extends ESTestCase { null, null, null - ), - null, - null, - false, - null, - null, - 0, - randomAlphaOfLengthBetween(3, 8), - 1, - 1, - 0, - 10, - null, - null + ) ) ); return null; @@ -734,7 +709,7 @@ public class ApiKeyServiceTests extends ESTestCase { } ActionListener.respondAndRelease( listener, - new SearchResponse( + SearchResponseUtils.successfulResponse( SearchHits.unpooled( new SearchHit[] { searchHit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), @@ -742,20 +717,7 @@ public class ApiKeyServiceTests extends ESTestCase { null, null, null - ), - null, - null, - false, - null, - null, - 0, - randomAlphaOfLengthBetween(3, 8), - 1, - 1, - 0, - 10, - null, - null + ) ) ); return null; @@ -1078,7 +1040,7 @@ public class ApiKeyServiceTests extends ESTestCase { final ActionListener listener = invocationOnMock.getArgument(1); ActionListener.respondAndRelease( listener, - new SearchResponse( + SearchResponseUtils.successfulResponse( SearchHits.unpooled( searchHits.toArray(SearchHit[]::new), new TotalHits(searchHits.size(), TotalHits.Relation.EQUAL_TO), @@ -1086,20 +1048,7 @@ public class ApiKeyServiceTests extends ESTestCase { null, null, null - ), - null, - null, - false, - null, - null, - 0, - randomAlphaOfLengthBetween(3, 8), - 1, - 1, - 0, - 10, - null, - null + ) ) ); return null; diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/service/IndexServiceAccountTokenStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/service/IndexServiceAccountTokenStoreTests.java index 33d3e6783b9e..e13bfbddd640 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/service/IndexServiceAccountTokenStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/service/IndexServiceAccountTokenStoreTests.java @@ -27,7 +27,6 @@ import org.elasticsearch.action.index.IndexResponse; import org.elasticsearch.action.search.ClearScrollRequest; import org.elasticsearch.action.search.ClearScrollResponse; import org.elasticsearch.action.search.SearchRequest; -import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.action.support.PlainActionFuture; import org.elasticsearch.client.internal.Client; import org.elasticsearch.client.internal.FilterClient; @@ -42,6 +41,7 @@ import org.elasticsearch.index.get.GetResult; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.XContentTestUtils; import org.elasticsearch.threadpool.ThreadPool; @@ -271,21 +271,8 @@ public class IndexServiceAccountTokenStoreTests extends ESTestCase { .toArray(SearchHit[]::new); ActionListener.respondAndRelease( l, - new SearchResponse( - SearchHits.unpooled(hits, new TotalHits(nhits, TotalHits.Relation.EQUAL_TO), randomFloat(), null, null, null), - null, - null, - false, - null, - null, - 0, - randomAlphaOfLengthBetween(3, 8), - 1, - 1, - 0, - 10, - null, - null + SearchResponseUtils.successfulResponse( + SearchHits.unpooled(hits, new TotalHits(nhits, TotalHits.Relation.EQUAL_TO), randomFloat(), null, null, null) ) ); } else if (r instanceof ClearScrollRequest) { diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java index ca84a9189d90..206c6379eaff 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authc/support/mapper/NativeRoleMappingStoreTests.java @@ -26,6 +26,7 @@ import org.elasticsearch.script.ScriptService; import org.elasticsearch.script.mustache.MustacheScriptEngine; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.ToXContent; @@ -352,21 +353,8 @@ public class NativeRoleMappingStoreTests extends ESTestCase { } ActionListener.respondAndRelease( listener, - new SearchResponse( - SearchHits.unpooled(new SearchHit[] { searchHit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), randomFloat()), - null, - null, - false, - null, - null, - 0, - randomAlphaOfLengthBetween(3, 8), - 1, - 1, - 0, - 10, - null, - null + SearchResponseUtils.successfulResponse( + SearchHits.unpooled(new SearchHit[] { searchHit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), randomFloat()) ) ); return null; diff --git a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativePrivilegeStoreTests.java b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativePrivilegeStoreTests.java index ed3949450cb9..0c09b4f4eb32 100644 --- a/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativePrivilegeStoreTests.java +++ b/x-pack/plugin/security/src/test/java/org/elasticsearch/xpack/security/authz/store/NativePrivilegeStoreTests.java @@ -43,6 +43,7 @@ import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.indices.IndexClosedException; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ClusterServiceUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.client.NoOpClient; @@ -930,7 +931,7 @@ public class NativePrivilegeStoreTests extends ESTestCase { private static SearchResponse buildSearchResponse(SearchHit[] hits) { var searchHits = new SearchHits(hits, new TotalHits(hits.length, TotalHits.Relation.EQUAL_TO), 0f); try { - return new SearchResponse(searchHits.asUnpooled(), null, null, false, false, null, 1, "_scrollId1", 1, 1, 0, 1, null, null); + return SearchResponseUtils.successfulResponse(searchHits.asUnpooled()); } finally { searchHits.decRef(); } diff --git a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/checkpoint/TimeBasedCheckpointProviderTests.java b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/checkpoint/TimeBasedCheckpointProviderTests.java index 468a14bc1db1..15a681d09373 100644 --- a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/checkpoint/TimeBasedCheckpointProviderTests.java +++ b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/checkpoint/TimeBasedCheckpointProviderTests.java @@ -13,7 +13,6 @@ import org.elasticsearch.action.ActionListener; import org.elasticsearch.action.LatchedActionListener; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.search.TransportSearchAction; import org.elasticsearch.client.internal.Client; import org.elasticsearch.client.internal.ParentTaskAssigningClient; @@ -25,6 +24,7 @@ import org.elasticsearch.core.Tuple; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; import org.elasticsearch.tasks.TaskId; import org.elasticsearch.test.ESTestCase; @@ -342,22 +342,7 @@ public class TimeBasedCheckpointProviderTests extends ESTestCase { } private static SearchResponse newSearchResponse(long totalHits) { - return new SearchResponse( - SearchHits.empty(new TotalHits(totalHits, TotalHits.Relation.EQUAL_TO), 0), - null, - null, - false, - false, - null, - 0, - null, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - null - ); + return SearchResponseUtils.successfulResponse(SearchHits.empty(new TotalHits(totalHits, TotalHits.Relation.EQUAL_TO), 0)); } @SuppressWarnings("unchecked") diff --git a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerFailureHandlingTests.java b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerFailureHandlingTests.java index eeef51bcbcb0..b9380ade1238 100644 --- a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerFailureHandlingTests.java +++ b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerFailureHandlingTests.java @@ -35,8 +35,7 @@ import org.elasticsearch.index.reindex.DeleteByQueryRequest; import org.elasticsearch.script.ScriptException; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; -import org.elasticsearch.search.profile.SearchProfileResults; -import org.elasticsearch.search.suggest.Suggest; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.core.common.notifications.Level; @@ -236,26 +235,7 @@ public class TransformIndexerFailureHandlingTests extends ESTestCase { @Override void doGetInitialProgress(SearchRequest request, ActionListener responseListener) { - ActionListener.respondAndRelease( - responseListener, - new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - // Simulate completely null aggs - null, - new Suggest(Collections.emptyList()), - false, - false, - new SearchProfileResults(Collections.emptyMap()), - 1, - "", - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ) - ); + ActionListener.respondAndRelease(responseListener, SearchResponseUtils.successfulResponse(SearchHits.EMPTY_WITH_TOTAL_HITS)); } @Override @@ -387,23 +367,7 @@ public class TransformIndexerFailureHandlingTests extends ESTestCase { null, null ); - SearchResponse searchResponse = new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - // Simulate completely null aggs - null, - new Suggest(Collections.emptyList()), - false, - false, - new SearchProfileResults(Collections.emptyMap()), - 1, - "", - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ); + SearchResponse searchResponse = SearchResponseUtils.successfulResponse(SearchHits.EMPTY_WITH_TOTAL_HITS); try { AtomicReference state = new AtomicReference<>(IndexerState.STOPPED); Function searchFunction = searchRequest -> searchResponse; @@ -516,22 +480,8 @@ public class TransformIndexerFailureHandlingTests extends ESTestCase { null ); - final SearchResponse searchResponse = new SearchResponse( - SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f), - // Simulate completely null aggs - null, - new Suggest(Collections.emptyList()), - false, - false, - new SearchProfileResults(Collections.emptyMap()), - 1, - "", - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY + final SearchResponse searchResponse = SearchResponseUtils.successfulResponse( + SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f) ); try { AtomicReference state = new AtomicReference<>(IndexerState.STOPPED); @@ -611,22 +561,8 @@ public class TransformIndexerFailureHandlingTests extends ESTestCase { null ); - final SearchResponse searchResponse = new SearchResponse( - SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f), - // Simulate completely null aggs - null, - new Suggest(Collections.emptyList()), - false, - false, - new SearchProfileResults(Collections.emptyMap()), - 1, - "", - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY + final SearchResponse searchResponse = SearchResponseUtils.successfulResponse( + SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f) ); try { AtomicReference state = new AtomicReference<>(IndexerState.STOPPED); @@ -709,22 +645,8 @@ public class TransformIndexerFailureHandlingTests extends ESTestCase { null ); - final SearchResponse searchResponse = new SearchResponse( - SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f), - // Simulate completely null aggs - null, - new Suggest(Collections.emptyList()), - false, - false, - new SearchProfileResults(Collections.emptyMap()), - 1, - "", - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY + final SearchResponse searchResponse = SearchResponseUtils.successfulResponse( + SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f) ); try { AtomicReference state = new AtomicReference<>(IndexerState.STOPPED); @@ -954,22 +876,8 @@ public class TransformIndexerFailureHandlingTests extends ESTestCase { } private static Function returnHit() { - return request -> new SearchResponse( - SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f), - // Simulate completely null aggs - null, - new Suggest(Collections.emptyList()), - false, - false, - new SearchProfileResults(Collections.emptyMap()), - 1, - "", - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY + return request -> SearchResponseUtils.successfulResponse( + SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f) ); } diff --git a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerStateTests.java b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerStateTests.java index e3a4ef118f61..4306e6dd8bf4 100644 --- a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerStateTests.java +++ b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerStateTests.java @@ -16,7 +16,6 @@ import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.support.ActionTestUtils; import org.elasticsearch.client.internal.Client; import org.elasticsearch.common.settings.Settings; @@ -27,8 +26,7 @@ import org.elasticsearch.index.reindex.BulkByScrollTask; import org.elasticsearch.index.reindex.DeleteByQueryRequest; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; -import org.elasticsearch.search.profile.SearchProfileResults; -import org.elasticsearch.search.suggest.Suggest; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.client.NoOpClient; import org.elasticsearch.test.junit.annotations.TestIssueLogging; @@ -87,22 +85,8 @@ import static org.mockito.Mockito.verify; public class TransformIndexerStateTests extends ESTestCase { - private static final SearchResponse ONE_HIT_SEARCH_RESPONSE = new SearchResponse( - SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f), - // Simulate completely null aggs - null, - new Suggest(Collections.emptyList()), - false, - false, - new SearchProfileResults(Collections.emptyMap()), - 1, - "", - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY + private static final SearchResponse ONE_HIT_SEARCH_RESPONSE = SearchResponseUtils.successfulResponse( + SearchHits.unpooled(new SearchHit[] { SearchHit.unpooled(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f) ); private Client client; diff --git a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerTests.java b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerTests.java index 644518538638..9e352c0e8903 100644 --- a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerTests.java +++ b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/TransformIndexerTests.java @@ -16,7 +16,6 @@ import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.action.support.ActionTestUtils; import org.elasticsearch.client.internal.Client; import org.elasticsearch.common.breaker.CircuitBreaker; @@ -28,8 +27,7 @@ import org.elasticsearch.index.reindex.BulkByScrollTask; import org.elasticsearch.index.reindex.DeleteByQueryRequest; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; -import org.elasticsearch.search.profile.SearchProfileResults; -import org.elasticsearch.search.suggest.Suggest; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.client.NoOpClient; import org.elasticsearch.threadpool.TestThreadPool; @@ -81,22 +79,8 @@ import static org.mockito.Mockito.mock; public class TransformIndexerTests extends ESTestCase { - private static final SearchResponse ONE_HIT_SEARCH_RESPONSE = new SearchResponse( - new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f), - // Simulate completely null aggs - null, - new Suggest(Collections.emptyList()), - false, - false, - new SearchProfileResults(Collections.emptyMap()), - 1, - "", - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY + private static final SearchResponse ONE_HIT_SEARCH_RESPONSE = SearchResponseUtils.successfulResponse( + new SearchHits(new SearchHit[] { new SearchHit(1) }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1.0f) ); private Client client; diff --git a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/CompositeBucketsChangeCollectorTests.java b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/CompositeBucketsChangeCollectorTests.java index a774a202f333..d6551c990e9d 100644 --- a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/CompositeBucketsChangeCollectorTests.java +++ b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/CompositeBucketsChangeCollectorTests.java @@ -8,10 +8,10 @@ package org.elasticsearch.xpack.transform.transforms.pivot; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.TermsQueryBuilder; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.aggregations.InternalAggregations; import org.elasticsearch.search.aggregations.bucket.composite.CompositeAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.composite.InternalComposite; @@ -109,24 +109,10 @@ public class CompositeBucketsChangeCollectorTests extends ESTestCase { return compositeBuckets; }); - InternalAggregations aggs = InternalAggregations.from(Collections.singletonList(composite)); - SearchResponse response = new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - aggs, - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - null - ); + SearchResponse response = SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS) + .aggregations(InternalAggregations.from(composite)) + .build(); try { collector.processSearchResponse(response); diff --git a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/DateHistogramFieldCollectorTests.java b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/DateHistogramFieldCollectorTests.java index a70bf930a7d5..20bdce2fccca 100644 --- a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/DateHistogramFieldCollectorTests.java +++ b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/DateHistogramFieldCollectorTests.java @@ -8,10 +8,10 @@ package org.elasticsearch.xpack.transform.transforms.pivot; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.aggregations.InternalAggregations; import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval; import org.elasticsearch.search.aggregations.metrics.InternalNumericMetricsAggregation; @@ -23,9 +23,9 @@ import org.elasticsearch.xpack.core.transform.transforms.pivot.SingleGroupSource import org.elasticsearch.xpack.transform.transforms.Function.ChangeCollector; import org.junit.Before; -import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import static org.hamcrest.CoreMatchers.instanceOf; @@ -171,22 +171,8 @@ public class DateHistogramFieldCollectorTests extends ESTestCase { } private static SearchResponse buildSearchResponse(SingleValue minTimestamp, SingleValue maxTimestamp) { - return new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - InternalAggregations.from(Arrays.asList(minTimestamp, maxTimestamp)), - null, - false, - null, - null, - 1, - null, - 1, - 1, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - null - ); + return SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS) + .aggregations(InternalAggregations.from(List.of(minTimestamp, maxTimestamp))) + .build(); } - } diff --git a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/PivotTests.java b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/PivotTests.java index 0a030d26016f..37817bc261be 100644 --- a/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/PivotTests.java +++ b/x-pack/plugin/transform/src/test/java/org/elasticsearch/xpack/transform/transforms/pivot/PivotTests.java @@ -25,6 +25,7 @@ import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.license.XPackLicenseState; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.SearchModule; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.aggregations.InternalAggregations; import org.elasticsearch.search.aggregations.bucket.composite.InternalComposite; import org.elasticsearch.test.ESTestCase; @@ -351,22 +352,7 @@ public class PivotTests extends ESTestCase { } private static SearchResponse searchResponseFromAggs(InternalAggregations aggs) { - return new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - aggs, - null, - false, - null, - null, - 1, - null, - 10, - 5, - 0, - 0, - ShardSearchFailure.EMPTY_ARRAY, - null - ); + return SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS).aggregations(aggs).shards(10, 5, 0).build(); } private class MyMockClient extends NoOpClient { @@ -397,22 +383,10 @@ public class PivotTests extends ESTestCase { } ActionListener.respondAndRelease( listener, - (Response) new SearchResponse( - SearchHits.EMPTY_WITH_TOTAL_HITS, - null, - null, - false, - null, - null, - 1, - null, - 10, - searchFailures.size() > 0 ? 0 : 5, - 0, - 0, - searchFailures.toArray(new ShardSearchFailure[searchFailures.size()]), - null - ) + (Response) SearchResponseUtils.response(SearchHits.EMPTY_WITH_TOTAL_HITS) + .shards(10, searchFailures.isEmpty() ? 5 : 0, 0) + .shardFailures(searchFailures) + .build() ); return; } diff --git a/x-pack/plugin/watcher/src/internalClusterTest/java/org/elasticsearch/xpack/watcher/condition/CompareConditionSearchTests.java b/x-pack/plugin/watcher/src/internalClusterTest/java/org/elasticsearch/xpack/watcher/condition/CompareConditionSearchTests.java index d97b0bd81a10..a15f18fb5c98 100644 --- a/x-pack/plugin/watcher/src/internalClusterTest/java/org/elasticsearch/xpack/watcher/condition/CompareConditionSearchTests.java +++ b/x-pack/plugin/watcher/src/internalClusterTest/java/org/elasticsearch/xpack/watcher/condition/CompareConditionSearchTests.java @@ -8,10 +8,10 @@ package org.elasticsearch.xpack.watcher.condition; import org.apache.lucene.search.TotalHits; import org.elasticsearch.action.search.SearchResponse; -import org.elasticsearch.action.search.ShardSearchFailure; import org.elasticsearch.index.shard.ShardId; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.SearchResponseUtils; import org.elasticsearch.search.SearchShardTarget; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.BucketOrder; @@ -104,22 +104,9 @@ public class CompareConditionSearchTests extends AbstractWatcherIntegrationTestC hit.score(1f); hit.shard(new SearchShardTarget("a", new ShardId("a", "indexUUID", 0), null)); - SearchResponse response = new SearchResponse( - SearchHits.unpooled(new SearchHit[] { hit }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1f), - null, - null, - false, - false, - null, - 1, - "", - 3, - 3, - 0, - 500L, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ); + SearchResponse response = SearchResponseUtils.response( + SearchHits.unpooled(new SearchHit[] { hit }, new TotalHits(1L, TotalHits.Relation.EQUAL_TO), 1f) + ).shards(3, 3, 0).build(); try { WatchExecutionContext ctx = mockExecutionContext("_watch_name", new Payload.XContent(response, ToXContent.EMPTY_PARAMS)); assertThat(condition.execute(ctx).met(), is(true)); diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherServiceTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherServiceTests.java index 24a4eede1b20..89d10564c8b9 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherServiceTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/WatcherServiceTests.java @@ -216,25 +216,7 @@ public class WatcherServiceTests extends ESTestCase { SearchHits searchHits = SearchHits.unpooled(hits, new TotalHits(count, TotalHits.Relation.EQUAL_TO), 1.0f); doAnswer(invocation -> { ActionListener listener = (ActionListener) invocation.getArguments()[2]; - ActionListener.respondAndRelease( - listener, - new SearchResponse( - searchHits, - null, - null, - false, - false, - null, - 1, - "scrollId", - 1, - 1, - 0, - 10, - ShardSearchFailure.EMPTY_ARRAY, - SearchResponse.Clusters.EMPTY - ) - ); + ActionListener.respondAndRelease(listener, SearchResponseUtils.response(searchHits).scrollId("scrollId").build()); return null; }).when(client).execute(eq(TransportSearchAction.TYPE), any(SearchRequest.class), anyActionListener()); diff --git a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/execution/TriggeredWatchStoreTests.java b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/execution/TriggeredWatchStoreTests.java index 776f649300aa..1cdb6debfbb8 100644 --- a/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/execution/TriggeredWatchStoreTests.java +++ b/x-pack/plugin/watcher/src/test/java/org/elasticsearch/xpack/watcher/execution/TriggeredWatchStoreTests.java @@ -240,22 +240,9 @@ public class TriggeredWatchStoreTests extends ESTestCase { hit.sourceRef(source); ActionListener.respondAndRelease( listener, - new SearchResponse( - SearchHits.unpooled(new SearchHit[] { hit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f), - null, - null, - false, - null, - null, - 1, - "_scrollId1", - 1, - 1, - 0, - 1, - null, - null - ) + SearchResponseUtils.response( + SearchHits.unpooled(new SearchHit[] { hit }, new TotalHits(1, TotalHits.Relation.EQUAL_TO), 1.0f) + ).scrollId("_scrollId1").build() ); } else if (request.scrollId().equals("_scrollId1")) { ActionListener.respondAndRelease(listener, SearchResponseUtils.emptyWithTotalHits("_scrollId2", 1, 1, 0, 1, null, null)); From a8958755a7e76a25bd9fef74f385083edf7dd705 Mon Sep 17 00:00:00 2001 From: Joe Gallo Date: Fri, 21 Feb 2025 08:00:10 -0500 Subject: [PATCH 02/27] Fix geoip databases index access after system feature migration (again) (#122938) --- docs/changelog/122938.yaml | 5 + .../ingest/geoip/FullClusterRestartIT.java | 20 ++++ .../metadata/IndexAbstractionResolver.java | 22 ++++- .../IndexAbstractionResolverTests.java | 92 +++++++++++++++---- 4 files changed, 118 insertions(+), 21 deletions(-) create mode 100644 docs/changelog/122938.yaml diff --git a/docs/changelog/122938.yaml b/docs/changelog/122938.yaml new file mode 100644 index 000000000000..cfb6e319c6cd --- /dev/null +++ b/docs/changelog/122938.yaml @@ -0,0 +1,5 @@ +pr: 122938 +summary: Fix geoip databases index access after system feature migration (again) +area: Ingest Node +type: bug +issues: [] diff --git a/modules/ingest-geoip/qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/ingest/geoip/FullClusterRestartIT.java b/modules/ingest-geoip/qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/ingest/geoip/FullClusterRestartIT.java index 0ba3b4ebb69f..15e85c23bf51 100644 --- a/modules/ingest-geoip/qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/ingest/geoip/FullClusterRestartIT.java +++ b/modules/ingest-geoip/qa/full-cluster-restart/src/javaRestTest/java/org/elasticsearch/ingest/geoip/FullClusterRestartIT.java @@ -123,6 +123,9 @@ public class FullClusterRestartIT extends ParameterizedFullClusterRestartTestCas // as should a normal get * assertBusy(() -> testGetStar(List.of("my-index-00001"), maybeSecurityIndex)); + + // and getting data streams + assertBusy(() -> testGetDatastreams()); } else { // after the upgrade, but before the migration, Kibana should work assertBusy(() -> testGetStarAsKibana(List.of("my-index-00001"), maybeSecurityIndex)); @@ -130,6 +133,9 @@ public class FullClusterRestartIT extends ParameterizedFullClusterRestartTestCas // as should a normal get * assertBusy(() -> testGetStar(List.of("my-index-00001"), maybeSecurityIndex)); + // and getting data streams + assertBusy(() -> testGetDatastreams()); + // migrate the system features and give the cluster a moment to settle Request migrateSystemFeatures = new Request("POST", "/_migration/system_features"); assertOK(client().performRequest(migrateSystemFeatures)); @@ -144,6 +150,9 @@ public class FullClusterRestartIT extends ParameterizedFullClusterRestartTestCas // as should a normal get * assertBusy(() -> testGetStar(List.of("my-index-00001"), maybeSecurityIndexReindexed)); + // and getting data streams + assertBusy(() -> testGetDatastreams()); + Request disableDownloader = new Request("PUT", "/_cluster/settings"); disableDownloader.setJsonEntity(""" {"persistent": {"ingest.geoip.downloader.enabled": false}} @@ -257,4 +266,15 @@ public class FullClusterRestartIT extends ParameterizedFullClusterRestartTestCas Map map = responseAsMap(response); assertThat(map.keySet(), is(new HashSet<>(indexNames))); } + + private void testGetDatastreams() throws IOException { + Request getStar = new Request("GET", "_data_stream"); + getStar.setOptions( + RequestOptions.DEFAULT.toBuilder().setWarningsHandler(WarningsHandler.PERMISSIVE) // we don't care about warnings, just errors + ); + Response response = client().performRequest(getStar); + assertOK(response); + + // note: we don't actually care about the response, just that there was one and that it didn't error out on us + } } diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java index fe7199f8332d..562d2363905d 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolver.java @@ -14,6 +14,7 @@ import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.common.regex.Regex; import org.elasticsearch.core.Nullable; import org.elasticsearch.core.Tuple; +import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexNotFoundException; import org.elasticsearch.indices.SystemIndices.SystemIndexAccessLevel; @@ -158,7 +159,26 @@ public class IndexAbstractionResolver { if (indexAbstraction.isSystem()) { // check if it is net new if (resolver.getNetNewSystemIndexPredicate().test(indexAbstraction.getName())) { - return isSystemIndexVisible(resolver, indexAbstraction); + // don't give this code any particular credit for being *correct*. it's just trying to resolve a combination of + // issues in a way that happens to *work*. there's probably a better way of writing things such that this won't + // be necessary, but for the moment, it happens to be expedient to write things this way. + + // unwrap the alias and re-run the function on the write index of the alias -- that is, the alias is visible if + // the concrete index that it refers to is visible + Index writeIndex = indexAbstraction.getWriteIndex(); + if (writeIndex == null) { + return false; + } else { + return isIndexVisible( + expression, + selectorString, + writeIndex.getName(), + indicesOptions, + metadata, + resolver, + includeDataStreams + ); + } } } diff --git a/server/src/test/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolverTests.java b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolverTests.java index a3ac361f5b05..24eb98952d74 100644 --- a/server/src/test/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolverTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/metadata/IndexAbstractionResolverTests.java @@ -29,6 +29,7 @@ import java.util.concurrent.TimeUnit; import java.util.function.Supplier; import static org.elasticsearch.index.mapper.MapperService.SINGLE_MAPPING_NAME; +import static org.elasticsearch.indices.SystemIndices.EXTERNAL_SYSTEM_INDEX_ACCESS_CONTROL_HEADER_KEY; import static org.elasticsearch.indices.SystemIndices.SYSTEM_INDEX_ACCESS_CONTROL_HEADER_KEY; import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder; import static org.hamcrest.Matchers.contains; @@ -218,18 +219,6 @@ public class IndexAbstractionResolverTests extends ESTestCase { assertThat(isIndexVisible("data-stream1", "failures"), is(true)); } - private boolean isIndexVisible(String index, String selector) { - return IndexAbstractionResolver.isIndexVisible( - "*", - selector, - index, - IndicesOptions.strictExpandHidden(), - metadata, - indexNameExpressionResolver, - true - ); - } - public void testIsNetNewSystemIndexVisible() { final Settings settings = Settings.builder() .put("index.number_of_replicas", 0) @@ -269,16 +258,71 @@ public class IndexAbstractionResolverTests extends ESTestCase { List.of(new SystemIndices.Feature("name", "description", List.of(fooDescriptor, barDescriptor))) ); - final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); - threadContext.putHeader(SYSTEM_INDEX_ACCESS_CONTROL_HEADER_KEY, "false"); - indexNameExpressionResolver = new IndexNameExpressionResolver(threadContext, systemIndices); - indexAbstractionResolver = new IndexAbstractionResolver(indexNameExpressionResolver); - metadata = Metadata.builder().put(foo, true).put(barReindexed, true).put(other, true).build(); - assertThat(isIndexVisible("other", "*"), is(true)); - assertThat(isIndexVisible(".foo", "*"), is(false)); - assertThat(isIndexVisible(".bar", "*"), is(false)); + // these indices options are for the GET _data_streams case + final IndicesOptions noHiddenNoAliases = IndicesOptions.builder() + .wildcardOptions( + IndicesOptions.WildcardOptions.builder() + .matchOpen(true) + .matchClosed(true) + .includeHidden(false) + .resolveAliases(false) + .build() + ) + .build(); + + { + final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + threadContext.putHeader(SYSTEM_INDEX_ACCESS_CONTROL_HEADER_KEY, "true"); + indexNameExpressionResolver = new IndexNameExpressionResolver(threadContext, systemIndices); + indexAbstractionResolver = new IndexAbstractionResolver(indexNameExpressionResolver); + + // this covers the GET * case -- with system access, you can see everything + assertThat(isIndexVisible("other", "*"), is(true)); + assertThat(isIndexVisible(".foo", "*"), is(true)); + assertThat(isIndexVisible(".bar", "*"), is(true)); + + // but if you don't ask for hidden and aliases, you won't see hidden indices or aliases, naturally + assertThat(isIndexVisible("other", "*", noHiddenNoAliases), is(true)); + assertThat(isIndexVisible(".foo", "*", noHiddenNoAliases), is(false)); + assertThat(isIndexVisible(".bar", "*", noHiddenNoAliases), is(false)); + } + + { + final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + threadContext.putHeader(SYSTEM_INDEX_ACCESS_CONTROL_HEADER_KEY, "false"); + indexNameExpressionResolver = new IndexNameExpressionResolver(threadContext, systemIndices); + indexAbstractionResolver = new IndexAbstractionResolver(indexNameExpressionResolver); + + // this covers the GET * case -- without system access, you can't see everything + assertThat(isIndexVisible("other", "*"), is(true)); + assertThat(isIndexVisible(".foo", "*"), is(false)); + assertThat(isIndexVisible(".bar", "*"), is(false)); + + // no difference here in the datastream case, you can't see these then, either + assertThat(isIndexVisible("other", "*", noHiddenNoAliases), is(true)); + assertThat(isIndexVisible(".foo", "*", noHiddenNoAliases), is(false)); + assertThat(isIndexVisible(".bar", "*", noHiddenNoAliases), is(false)); + } + + { + final ThreadContext threadContext = new ThreadContext(Settings.EMPTY); + threadContext.putHeader(SYSTEM_INDEX_ACCESS_CONTROL_HEADER_KEY, "true"); + threadContext.putHeader(EXTERNAL_SYSTEM_INDEX_ACCESS_CONTROL_HEADER_KEY, "some-elastic-product"); + indexNameExpressionResolver = new IndexNameExpressionResolver(threadContext, systemIndices); + indexAbstractionResolver = new IndexAbstractionResolver(indexNameExpressionResolver); + + // this covers the GET * case -- with product (only) access, you can't see everything + assertThat(isIndexVisible("other", "*"), is(true)); + assertThat(isIndexVisible(".foo", "*"), is(false)); + assertThat(isIndexVisible(".bar", "*"), is(false)); + + // no difference here in the datastream case, you can't see these then, either + assertThat(isIndexVisible("other", "*", noHiddenNoAliases), is(true)); + assertThat(isIndexVisible(".foo", "*", noHiddenNoAliases), is(false)); + assertThat(isIndexVisible(".bar", "*", noHiddenNoAliases), is(false)); + } } private static XContentBuilder mappings() { @@ -306,4 +350,12 @@ public class IndexAbstractionResolverTests extends ESTestCase { private List resolveAbstractions(List expressions, IndicesOptions indicesOptions, Supplier> mask) { return indexAbstractionResolver.resolveIndexAbstractions(expressions, indicesOptions, metadata, mask, (idx) -> true, true); } + + private boolean isIndexVisible(String index, String selector) { + return isIndexVisible(index, selector, IndicesOptions.strictExpandHidden()); + } + + private boolean isIndexVisible(String index, String selector, IndicesOptions indicesOptions) { + return IndexAbstractionResolver.isIndexVisible("*", selector, index, indicesOptions, metadata, indexNameExpressionResolver, true); + } } From 71f80c4213dc5e88ab9d57d3c14356b51efe629a Mon Sep 17 00:00:00 2001 From: Tim Grein Date: Fri, 21 Feb 2025 14:27:40 +0100 Subject: [PATCH 03/27] [Inference API] Follow-up for add rerouting attributes PR (#123121) --- .../inference/telemetry/InferenceStats.java | 49 +++++++------------ 1 file changed, 19 insertions(+), 30 deletions(-) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/telemetry/InferenceStats.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/telemetry/InferenceStats.java index 45e22870f123..17c91b81233f 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/telemetry/InferenceStats.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/telemetry/InferenceStats.java @@ -16,12 +16,9 @@ import org.elasticsearch.telemetry.metric.LongHistogram; import org.elasticsearch.telemetry.metric.MeterRegistry; import org.elasticsearch.xpack.core.inference.action.BaseInferenceActionRequest; +import java.util.HashMap; import java.util.Map; import java.util.Objects; -import java.util.stream.Collectors; -import java.util.stream.Stream; - -import static java.util.Map.entry; public record InferenceStats(LongCounter requestCount, LongHistogram inferenceDuration) { @@ -45,18 +42,16 @@ public record InferenceStats(LongCounter requestCount, LongHistogram inferenceDu ); } - private static Map toMap(Stream> stream) { - return stream.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - public static Map modelAttributes(Model model) { - var stream = Stream.>builder() - .add(entry("service", model.getConfigurations().getService())) - .add(entry("task_type", model.getTaskType().toString())); - if (model.getServiceSettings().modelId() != null) { - stream.add(entry("model_id", model.getServiceSettings().modelId())); + var modelAttributesMap = new HashMap(); + modelAttributesMap.put("service", model.getConfigurations().getService()); + modelAttributesMap.put("task_type", model.getTaskType().toString()); + + if (Objects.nonNull(model.getServiceSettings().modelId())) { + modelAttributesMap.put("model_id", model.getServiceSettings().modelId()); } - return toMap(stream.build()); + + return modelAttributesMap; } public static Map routingAttributes(BaseInferenceActionRequest request, String nodeIdHandlingRequest) { @@ -64,24 +59,18 @@ public record InferenceStats(LongCounter requestCount, LongHistogram inferenceDu } public static Map modelAttributes(UnparsedModel model) { - var unknownModelAttributes = Stream.>builder() - .add(entry("service", model.service())) - .add(entry("task_type", model.taskType().toString())) - .build(); - - return toMap(unknownModelAttributes); + return Map.of("service", model.service(), "task_type", model.taskType().toString()); } - public static Map responseAttributes(@Nullable Throwable t) { - var stream = switch (t) { - case null -> Stream.>of(entry("status_code", 200)); - case ElasticsearchStatusException ese -> Stream.>builder() - .add(entry("status_code", ese.status().getStatus())) - .add(entry("error.type", String.valueOf(ese.status().getStatus()))) - .build(); - default -> Stream.>of(entry("error.type", t.getClass().getSimpleName())); - }; + public static Map responseAttributes(@Nullable Throwable throwable) { + if (Objects.isNull(throwable)) { + return Map.of("status_code", 200); + } - return toMap(stream); + if (throwable instanceof ElasticsearchStatusException ese) { + return Map.of("status_code", ese.status().getStatus(), "error.type", String.valueOf(ese.status().getStatus())); + } + + return Map.of("error.type", throwable.getClass().getSimpleName()); } } From b404a8b1f5ab5ea3ad3a60c8683689ef5acc032a Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 22 Feb 2025 00:32:24 +1100 Subject: [PATCH 04/27] Mute org.elasticsearch.index.mapper.extras.ScaledFloatFieldMapperTests testBlockLoaderFromRowStrideReaderWithSyntheticSource #123145 --- muted-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index 6fd12c90ea6b..8186450b7777 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -395,6 +395,9 @@ tests: - class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT method: test {fork.ForkWithWhereSortAndLimit} issue: https://github.com/elastic/elasticsearch/issues/123131 +- class: org.elasticsearch.index.mapper.extras.ScaledFloatFieldMapperTests + method: testBlockLoaderFromRowStrideReaderWithSyntheticSource + issue: https://github.com/elastic/elasticsearch/issues/123145 # Examples: # From 698bf31c6874917a52d540721c95d64d73443b10 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 22 Feb 2025 00:52:59 +1100 Subject: [PATCH 05/27] Mute org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT testStopQueryLocal #121672 --- muted-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index 8186450b7777..73a2f0c96c80 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -398,6 +398,9 @@ tests: - class: org.elasticsearch.index.mapper.extras.ScaledFloatFieldMapperTests method: testBlockLoaderFromRowStrideReaderWithSyntheticSource issue: https://github.com/elastic/elasticsearch/issues/123145 +- class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT + method: testStopQueryLocal + issue: https://github.com/elastic/elasticsearch/issues/121672 # Examples: # From 5f99708187007f6ee8747c2ec16e8fdb79872965 Mon Sep 17 00:00:00 2001 From: Jan Kuipers <148754765+jan-elastic@users.noreply.github.com> Date: Fri, 21 Feb 2025 15:29:50 +0100 Subject: [PATCH 06/27] Refactor EmbeddingRequestChunker (#122818) * refactor * inference generics * more refactor * unify naming * remove interface "EmbeddingInt" * more renaming * javadoc * revert accidental changeas * remove ununsed EmbeddingRequestChunker.EmbeddingType * polish * support chunking for text embedding bits * Polish error messagex * fix VoyageAI conflicts --- ...se.java => ChunkedInferenceEmbedding.java} | 26 +- .../ChunkedInferenceEmbeddingByte.java | 45 -- .../ChunkedInferenceEmbeddingFloat.java | 45 -- .../core/inference/results/EmbeddingInt.java | 12 - .../inference/results/EmbeddingResults.java | 51 ++ .../results/InferenceByteEmbedding.java | 95 ---- .../InferenceTextEmbeddingByteResults.java | 109 ---- .../results/LegacyTextEmbeddingResults.java | 6 +- .../results/SparseEmbeddingResults.java | 46 +- ...ults.java => TextEmbeddingBitResults.java} | 17 +- .../results/TextEmbeddingByteResults.java | 214 ++++++++ ...ts.java => TextEmbeddingFloatResults.java} | 76 ++- ...bedding.java => TextEmbeddingResults.java} | 4 +- .../inference/results/TextEmbeddingUtils.java | 14 - .../TestDenseInferenceServiceExtension.java | 18 +- .../TestSparseInferenceServiceExtension.java | 6 +- .../InferenceNamedWriteablesProvider.java | 16 +- .../chunking/EmbeddingRequestChunker.java | 483 ++++-------------- ...baCloudSearchEmbeddingsResponseEntity.java | 13 +- .../AmazonBedrockEmbeddingsResponse.java | 27 +- .../CohereEmbeddingsResponseEntity.java | 22 +- ...oogleAiStudioEmbeddingsResponseEntity.java | 13 +- ...oogleVertexAiEmbeddingsResponseEntity.java | 13 +- .../HuggingFaceEmbeddingsResponseEntity.java | 21 +- .../IbmWatsonxEmbeddingsResponseEntity.java | 13 +- .../JinaAIEmbeddingsResponseEntity.java | 13 +- .../OpenAiEmbeddingsResponseEntity.java | 13 +- .../VoyageAIEmbeddingsResponseEntity.java | 27 +- .../inference/services/ServiceUtils.java | 8 +- .../AlibabaCloudSearchService.java | 9 - .../amazonbedrock/AmazonBedrockService.java | 1 - .../azureaistudio/AzureAiStudioService.java | 1 - .../azureopenai/AzureOpenAiService.java | 1 - .../services/cohere/CohereService.java | 1 - .../elastic/ElasticInferenceService.java | 4 +- .../ElasticsearchInternalService.java | 30 +- .../googleaistudio/GoogleAiStudioService.java | 1 - .../googlevertexai/GoogleVertexAiService.java | 1 - .../huggingface/HuggingFaceService.java | 1 - .../elser/HuggingFaceElserService.java | 15 +- .../ibmwatsonx/IbmWatsonxService.java | 1 - .../services/jinaai/JinaAIService.java | 1 - .../services/mistral/MistralService.java | 1 - .../services/openai/OpenAiService.java | 1 - .../TextEmbeddingModelValidator.java | 10 +- .../services/voyageai/VoyageAIService.java | 1 - .../ShardBulkInferenceActionFilterTests.java | 4 +- .../EmbeddingRequestChunkerTests.java | 290 +++++------ .../AmazonBedrockActionCreatorTests.java | 6 +- ...udSearchEmbeddingsResponseEntityTests.java | 12 +- ...AiStudioEmbeddingsResponseEntityTests.java | 9 +- .../CohereEmbeddingsResponseEntityTests.java | 57 ++- ...AiStudioEmbeddingsResponseEntityTests.java | 15 +- ...VertexAiEmbeddingsResponseEntityTests.java | 15 +- ...gingFaceEmbeddingsResponseEntityTests.java | 50 +- ...mWatsonxEmbeddingsResponseEntityTests.java | 15 +- .../JinaAIEmbeddingsResponseEntityTests.java | 34 +- .../OpenAiEmbeddingsResponseEntityTests.java | 34 +- ...VoyageAIEmbeddingsResponseEntityTests.java | 30 +- .../mapper/SemanticTextFieldTests.java | 57 +-- .../queries/SemanticQueryBuilderTests.java | 4 +- .../rest/BaseInferenceActionTests.java | 5 +- ...java => TextEmbeddingBitResultsTests.java} | 53 +- ...ava => TextEmbeddingByteResultsTests.java} | 52 +- .../results/TextEmbeddingResultsTests.java | 62 +-- .../inference/services/ServiceUtilsTests.java | 16 +- .../AlibabaCloudSearchServiceTests.java | 62 +-- .../AmazonBedrockServiceTests.java | 54 +- .../AzureAiStudioServiceTests.java | 25 +- .../azureopenai/AzureOpenAiServiceTests.java | 25 +- .../services/cohere/CohereServiceTests.java | 43 +- .../elastic/ElasticInferenceServiceTests.java | 9 +- .../ElasticsearchInternalServiceTests.java | 88 ++-- .../GoogleAiStudioServiceTests.java | 27 +- .../HuggingFaceElserServiceTests.java | 9 +- .../huggingface/HuggingFaceServiceTests.java | 25 +- .../ibmwatsonx/IbmWatsonxServiceTests.java | 27 +- .../services/jinaai/JinaAIServiceTests.java | 25 +- .../services/mistral/MistralServiceTests.java | 27 +- .../services/openai/OpenAiServiceTests.java | 27 +- .../TextEmbeddingModelValidatorTests.java | 12 +- .../voyageai/VoyageAIServiceTests.java | 25 +- 82 files changed, 1250 insertions(+), 1626 deletions(-) rename x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/{ChunkedInferenceEmbeddingSparse.java => ChunkedInferenceEmbedding.java} (58%) delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbeddingByte.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbeddingFloat.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingInt.java create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingResults.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceByteEmbedding.java delete mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceTextEmbeddingByteResults.java rename x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/{InferenceTextEmbeddingBitResults.java => TextEmbeddingBitResults.java} (83%) create mode 100644 x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingByteResults.java rename x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/{InferenceTextEmbeddingFloatResults.java => TextEmbeddingFloatResults.java} (70%) rename x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/{TextEmbedding.java => TextEmbeddingResults.java} (78%) rename x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/{InferenceTextEmbeddingBitResultsTests.java => TextEmbeddingBitResultsTests.java} (56%) rename x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/{InferenceTextEmbeddingByteResultsTests.java => TextEmbeddingByteResultsTests.java} (56%) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbeddingSparse.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbedding.java similarity index 58% rename from x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbeddingSparse.java rename to x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbedding.java index 37bf92e0dbfc..e723a3b4f8f6 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbeddingSparse.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbedding.java @@ -7,12 +7,8 @@ package org.elasticsearch.xpack.core.inference.results; -import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.inference.ChunkedInference; -import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContent; -import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xpack.core.ml.search.WeightedToken; import java.io.IOException; import java.util.ArrayList; @@ -21,7 +17,7 @@ import java.util.List; import static org.elasticsearch.xpack.core.inference.results.TextEmbeddingUtils.validateInputSizeAgainstEmbeddings; -public record ChunkedInferenceEmbeddingSparse(List chunks) implements ChunkedInference { +public record ChunkedInferenceEmbedding(List chunks) implements ChunkedInference { public static List listOf(List inputs, SparseEmbeddingResults sparseEmbeddingResults) { validateInputSizeAgainstEmbeddings(inputs, sparseEmbeddingResults.embeddings().size()); @@ -29,9 +25,9 @@ public record ChunkedInferenceEmbeddingSparse(List chunks) var results = new ArrayList(inputs.size()); for (int i = 0; i < inputs.size(); i++) { results.add( - new ChunkedInferenceEmbeddingSparse( + new ChunkedInferenceEmbedding( List.of( - new SparseEmbeddingChunk( + new SparseEmbeddingResults.Chunk( sparseEmbeddingResults.embeddings().get(i).tokens(), inputs.get(i), new TextOffset(0, inputs.get(i).length()) @@ -47,21 +43,9 @@ public record ChunkedInferenceEmbeddingSparse(List chunks) @Override public Iterator chunksAsMatchedTextAndByteReference(XContent xcontent) throws IOException { var asChunk = new ArrayList(); - for (var chunk : chunks) { - asChunk.add(new Chunk(chunk.matchedText(), chunk.offset(), toBytesReference(xcontent, chunk.weightedTokens()))); + for (var chunk : chunks()) { + asChunk.add(chunk.toChunk(xcontent)); } return asChunk.iterator(); } - - private static BytesReference toBytesReference(XContent xContent, List tokens) throws IOException { - XContentBuilder b = XContentBuilder.builder(xContent); - b.startObject(); - for (var weightedToken : tokens) { - weightedToken.toXContent(b, ToXContent.EMPTY_PARAMS); - } - b.endObject(); - return BytesReference.bytes(b); - } - - public record SparseEmbeddingChunk(List weightedTokens, String matchedText, TextOffset offset) {} } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbeddingByte.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbeddingByte.java deleted file mode 100644 index c2f70b0be291..000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbeddingByte.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -package org.elasticsearch.xpack.core.inference.results; - -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.inference.ChunkedInference; -import org.elasticsearch.xcontent.XContent; -import org.elasticsearch.xcontent.XContentBuilder; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -public record ChunkedInferenceEmbeddingByte(List chunks) implements ChunkedInference { - - @Override - public Iterator chunksAsMatchedTextAndByteReference(XContent xcontent) throws IOException { - var asChunk = new ArrayList(); - for (var chunk : chunks) { - asChunk.add(new Chunk(chunk.matchedText(), chunk.offset(), toBytesReference(xcontent, chunk.embedding()))); - } - return asChunk.iterator(); - } - - /** - * Serialises the {@code value} array, according to the provided {@link XContent}, into a {@link BytesReference}. - */ - private static BytesReference toBytesReference(XContent xContent, byte[] value) throws IOException { - XContentBuilder builder = XContentBuilder.builder(xContent); - builder.startArray(); - for (byte v : value) { - builder.value(v); - } - builder.endArray(); - return BytesReference.bytes(builder); - } - - public record ByteEmbeddingChunk(byte[] embedding, String matchedText, TextOffset offset) {} -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbeddingFloat.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbeddingFloat.java deleted file mode 100644 index 651d135b761d..000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/ChunkedInferenceEmbeddingFloat.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -package org.elasticsearch.xpack.core.inference.results; - -import org.elasticsearch.common.bytes.BytesReference; -import org.elasticsearch.inference.ChunkedInference; -import org.elasticsearch.xcontent.XContent; -import org.elasticsearch.xcontent.XContentBuilder; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -public record ChunkedInferenceEmbeddingFloat(List chunks) implements ChunkedInference { - - @Override - public Iterator chunksAsMatchedTextAndByteReference(XContent xcontent) throws IOException { - var asChunk = new ArrayList(); - for (var chunk : chunks) { - asChunk.add(new Chunk(chunk.matchedText(), chunk.offset(), toBytesReference(xcontent, chunk.embedding()))); - } - return asChunk.iterator(); - } - - /** - * Serialises the {@code value} array, according to the provided {@link XContent}, into a {@link BytesReference}. - */ - private static BytesReference toBytesReference(XContent xContent, float[] value) throws IOException { - XContentBuilder b = XContentBuilder.builder(xContent); - b.startArray(); - for (float v : value) { - b.value(v); - } - b.endArray(); - return BytesReference.bytes(b); - } - - public record FloatEmbeddingChunk(float[] embedding, String matchedText, TextOffset offset) {} -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingInt.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingInt.java deleted file mode 100644 index 05fc8a3cef1b..000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingInt.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -package org.elasticsearch.xpack.core.inference.results; - -public interface EmbeddingInt { - int getSize(); -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingResults.java new file mode 100644 index 000000000000..c6f4c6915024 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/EmbeddingResults.java @@ -0,0 +1,51 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.core.inference.results; + +import org.elasticsearch.inference.ChunkedInference; +import org.elasticsearch.inference.InferenceServiceResults; +import org.elasticsearch.xcontent.XContent; + +import java.io.IOException; +import java.util.List; + +/** + * The results of a call to the inference service that contains embeddings (sparse or dense). + * A call to the inference service may contain multiple input texts, so this results may + * contain multiple results. + */ +public interface EmbeddingResults> + extends + InferenceServiceResults { + + /** + * A resulting embedding together with its input text. + */ + interface Chunk { + ChunkedInference.Chunk toChunk(XContent xcontent) throws IOException; + + String matchedText(); + + ChunkedInference.TextOffset offset(); + } + + /** + * A resulting embedding for one of the input texts to the inference service. + */ + interface Embedding { + /** + * Combines the resulting embedding with the input into a chunk. + */ + C toChunk(String text, ChunkedInference.TextOffset offset); + } + + /** + * The resulting list of embeddings for the input texts to the inference service. + */ + List embeddings(); +} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceByteEmbedding.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceByteEmbedding.java deleted file mode 100644 index 7d7176a9a5a5..000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceByteEmbedding.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - * - * this file was contributed to by a generative AI - */ - -package org.elasticsearch.xpack.core.inference.results; - -import org.elasticsearch.common.Strings; -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.io.stream.Writeable; -import org.elasticsearch.xcontent.ToXContentObject; -import org.elasticsearch.xcontent.XContentBuilder; - -import java.io.IOException; -import java.util.Arrays; -import java.util.List; - -public record InferenceByteEmbedding(byte[] values) implements Writeable, ToXContentObject, EmbeddingInt { - public static final String EMBEDDING = "embedding"; - - public InferenceByteEmbedding(StreamInput in) throws IOException { - this(in.readByteArray()); - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeByteArray(values); - } - - public static InferenceByteEmbedding of(List embeddingValuesList) { - byte[] embeddingValues = new byte[embeddingValuesList.size()]; - for (int i = 0; i < embeddingValuesList.size(); i++) { - embeddingValues[i] = embeddingValuesList.get(i); - } - return new InferenceByteEmbedding(embeddingValues); - } - - @Override - public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { - builder.startObject(); - - builder.startArray(EMBEDDING); - for (byte value : values) { - builder.value(value); - } - builder.endArray(); - - builder.endObject(); - return builder; - } - - @Override - public String toString() { - return Strings.toString(this); - } - - float[] toFloatArray() { - float[] floatArray = new float[values.length]; - for (int i = 0; i < values.length; i++) { - floatArray[i] = ((Byte) values[i]).floatValue(); - } - return floatArray; - } - - double[] toDoubleArray() { - double[] doubleArray = new double[values.length]; - for (int i = 0; i < values.length; i++) { - doubleArray[i] = ((Byte) values[i]).doubleValue(); - } - return doubleArray; - } - - @Override - public int getSize() { - return values().length; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - InferenceByteEmbedding embedding = (InferenceByteEmbedding) o; - return Arrays.equals(values, embedding.values); - } - - @Override - public int hashCode() { - return Arrays.hashCode(values); - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceTextEmbeddingByteResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceTextEmbeddingByteResults.java deleted file mode 100644 index 1ae54220508c..000000000000 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceTextEmbeddingByteResults.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - * - * this file was contributed to by a generative AI - */ - -package org.elasticsearch.xpack.core.inference.results; - -import org.elasticsearch.common.io.stream.StreamInput; -import org.elasticsearch.common.io.stream.StreamOutput; -import org.elasticsearch.common.xcontent.ChunkedToXContentHelper; -import org.elasticsearch.inference.InferenceResults; -import org.elasticsearch.inference.InferenceServiceResults; -import org.elasticsearch.xcontent.ToXContent; -import org.elasticsearch.xpack.core.ml.inference.results.MlTextEmbeddingResults; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * Writes a text embedding result in the follow json format - * { - * "text_embedding_bytes": [ - * { - * "embedding": [ - * 23 - * ] - * }, - * { - * "embedding": [ - * -23 - * ] - * } - * ] - * } - */ -public record InferenceTextEmbeddingByteResults(List embeddings) implements InferenceServiceResults, TextEmbedding { - public static final String NAME = "text_embedding_service_byte_results"; - public static final String TEXT_EMBEDDING_BYTES = "text_embedding_bytes"; - - public InferenceTextEmbeddingByteResults(StreamInput in) throws IOException { - this(in.readCollectionAsList(InferenceByteEmbedding::new)); - } - - @Override - public int getFirstEmbeddingSize() { - return TextEmbeddingUtils.getFirstEmbeddingSize(new ArrayList<>(embeddings)); - } - - @Override - public Iterator toXContentChunked(ToXContent.Params params) { - return ChunkedToXContentHelper.array(TEXT_EMBEDDING_BYTES, embeddings.iterator()); - } - - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeCollection(embeddings); - } - - @Override - public String getWriteableName() { - return NAME; - } - - @Override - public List transformToCoordinationFormat() { - return embeddings.stream() - .map(embedding -> new MlTextEmbeddingResults(TEXT_EMBEDDING_BYTES, embedding.toDoubleArray(), false)) - .toList(); - } - - @Override - @SuppressWarnings("deprecation") - public List transformToLegacyFormat() { - var legacyEmbedding = new LegacyTextEmbeddingResults( - embeddings.stream().map(embedding -> new LegacyTextEmbeddingResults.Embedding(embedding.toFloatArray())).toList() - ); - - return List.of(legacyEmbedding); - } - - public Map asMap() { - Map map = new LinkedHashMap<>(); - map.put(TEXT_EMBEDDING_BYTES, embeddings); - - return map; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - InferenceTextEmbeddingByteResults that = (InferenceTextEmbeddingByteResults) o; - return Objects.equals(embeddings, that.embeddings); - } - - @Override - public int hashCode() { - return Objects.hash(embeddings); - } -} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/LegacyTextEmbeddingResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/LegacyTextEmbeddingResults.java index 84a0928cae0d..60bbeb624b53 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/LegacyTextEmbeddingResults.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/LegacyTextEmbeddingResults.java @@ -44,7 +44,7 @@ import java.util.Objects; * * Legacy text embedding results represents what was returned prior to the * {@link org.elasticsearch.TransportVersions#V_8_12_0} version. - * @deprecated use {@link InferenceTextEmbeddingFloatResults} instead + * @deprecated use {@link TextEmbeddingFloatResults} instead */ @Deprecated public record LegacyTextEmbeddingResults(List embeddings) implements InferenceResults { @@ -114,8 +114,8 @@ public record LegacyTextEmbeddingResults(List embeddings) implements return Objects.hash(embeddings); } - public InferenceTextEmbeddingFloatResults transformToTextEmbeddingResults() { - return new InferenceTextEmbeddingFloatResults(this); + public TextEmbeddingFloatResults transformToTextEmbeddingResults() { + return new TextEmbeddingFloatResults(this); } public record Embedding(float[] values) implements Writeable, ToXContentObject { diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbeddingResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbeddingResults.java index dd8229c604ec..894e8c6c97bf 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbeddingResults.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/SparseEmbeddingResults.java @@ -9,16 +9,18 @@ package org.elasticsearch.xpack.core.inference.results; import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesReference; 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.xcontent.ChunkedToXContentHelper; +import org.elasticsearch.inference.ChunkedInference; import org.elasticsearch.inference.InferenceResults; -import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.inference.TaskType; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.ToXContentObject; +import org.elasticsearch.xcontent.XContent; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xpack.core.ml.inference.results.TextExpansionResults; import org.elasticsearch.xpack.core.ml.search.WeightedToken; @@ -33,13 +35,15 @@ import java.util.stream.Collectors; import static org.elasticsearch.xpack.core.ml.inference.trainedmodel.InferenceConfig.DEFAULT_RESULTS_FIELD; -public record SparseEmbeddingResults(List embeddings) implements InferenceServiceResults { +public record SparseEmbeddingResults(List embeddings) + implements + EmbeddingResults { public static final String NAME = "sparse_embedding_results"; public static final String SPARSE_EMBEDDING = TaskType.SPARSE_EMBEDDING.toString(); public SparseEmbeddingResults(StreamInput in) throws IOException { - this(in.readCollectionAsList(Embedding::new)); + this(in.readCollectionAsList(SparseEmbeddingResults.Embedding::new)); } public static SparseEmbeddingResults of(List results) { @@ -47,7 +51,9 @@ public record SparseEmbeddingResults(List embeddings) implements Infe for (InferenceResults result : results) { if (result instanceof TextExpansionResults expansionResults) { - embeddings.add(Embedding.create(expansionResults.getWeightedTokens(), expansionResults.isTruncated())); + embeddings.add( + SparseEmbeddingResults.Embedding.create(expansionResults.getWeightedTokens(), expansionResults.isTruncated()) + ); } else if (result instanceof org.elasticsearch.xpack.core.ml.inference.results.ErrorInferenceResults errorResult) { if (errorResult.getException() instanceof ElasticsearchStatusException statusException) { throw statusException; @@ -87,7 +93,7 @@ public record SparseEmbeddingResults(List embeddings) implements Infe public Map asMap() { Map map = new LinkedHashMap<>(); - var embeddingList = embeddings.stream().map(Embedding::asMap).toList(); + var embeddingList = embeddings.stream().map(SparseEmbeddingResults.Embedding::asMap).toList(); map.put(SPARSE_EMBEDDING, embeddingList); return map; @@ -114,7 +120,11 @@ public record SparseEmbeddingResults(List embeddings) implements Infe .toList(); } - public record Embedding(List tokens, boolean isTruncated) implements Writeable, ToXContentObject { + public record Embedding(List tokens, boolean isTruncated) + implements + Writeable, + ToXContentObject, + EmbeddingResults.Embedding { public static final String EMBEDDING = "embedding"; public static final String IS_TRUNCATED = "is_truncated"; @@ -163,5 +173,29 @@ public record SparseEmbeddingResults(List embeddings) implements Infe public String toString() { return Strings.toString(this); } + + @Override + public Chunk toChunk(String text, ChunkedInference.TextOffset offset) { + return new Chunk(tokens, text, offset); + } + } + + public record Chunk(List weightedTokens, String matchedText, ChunkedInference.TextOffset offset) + implements + EmbeddingResults.Chunk { + + public ChunkedInference.Chunk toChunk(XContent xcontent) throws IOException { + return new ChunkedInference.Chunk(matchedText, offset, toBytesReference(xcontent, weightedTokens)); + } + + private static BytesReference toBytesReference(XContent xContent, List tokens) throws IOException { + XContentBuilder b = XContentBuilder.builder(xContent); + b.startObject(); + for (var weightedToken : tokens) { + weightedToken.toXContent(b, ToXContent.EMPTY_PARAMS); + } + b.endObject(); + return BytesReference.bytes(b); + } } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceTextEmbeddingBitResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingBitResults.java similarity index 83% rename from x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceTextEmbeddingBitResults.java rename to x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingBitResults.java index 887c07558ab7..ba4a770b0484 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceTextEmbeddingBitResults.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingBitResults.java @@ -13,12 +13,10 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.xcontent.ChunkedToXContentHelper; import org.elasticsearch.inference.InferenceResults; -import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xpack.core.ml.inference.results.MlTextEmbeddingResults; import java.io.IOException; -import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; @@ -42,17 +40,22 @@ import java.util.Objects; * ] * } */ -public record InferenceTextEmbeddingBitResults(List embeddings) implements InferenceServiceResults, TextEmbedding { +public record TextEmbeddingBitResults(List embeddings) + implements + TextEmbeddingResults { public static final String NAME = "text_embedding_service_bit_results"; public static final String TEXT_EMBEDDING_BITS = "text_embedding_bits"; - public InferenceTextEmbeddingBitResults(StreamInput in) throws IOException { - this(in.readCollectionAsList(InferenceByteEmbedding::new)); + public TextEmbeddingBitResults(StreamInput in) throws IOException { + this(in.readCollectionAsList(TextEmbeddingByteResults.Embedding::new)); } @Override public int getFirstEmbeddingSize() { - return TextEmbeddingUtils.getFirstEmbeddingSize(new ArrayList<>(embeddings)); + if (embeddings.isEmpty()) { + throw new IllegalStateException("Embeddings list is empty"); + } + return embeddings.getFirst().values().length; } @Override @@ -98,7 +101,7 @@ public record InferenceTextEmbeddingBitResults(List embe public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - InferenceTextEmbeddingBitResults that = (InferenceTextEmbeddingBitResults) o; + TextEmbeddingBitResults that = (TextEmbeddingBitResults) o; return Objects.equals(embeddings, that.embeddings); } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingByteResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingByteResults.java new file mode 100644 index 000000000000..f8268d7bd468 --- /dev/null +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingByteResults.java @@ -0,0 +1,214 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + * + * this file was contributed to by a generative AI + */ + +package org.elasticsearch.xpack.core.inference.results; + +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesReference; +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.xcontent.ChunkedToXContentHelper; +import org.elasticsearch.inference.ChunkedInference; +import org.elasticsearch.inference.InferenceResults; +import org.elasticsearch.xcontent.ToXContent; +import org.elasticsearch.xcontent.ToXContentObject; +import org.elasticsearch.xcontent.XContent; +import org.elasticsearch.xcontent.XContentBuilder; +import org.elasticsearch.xpack.core.ml.inference.results.MlTextEmbeddingResults; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * Writes a text embedding result in the follow json format + * { + * "text_embedding_bytes": [ + * { + * "embedding": [ + * 23 + * ] + * }, + * { + * "embedding": [ + * -23 + * ] + * } + * ] + * } + */ +public record TextEmbeddingByteResults(List embeddings) + implements + TextEmbeddingResults { + public static final String NAME = "text_embedding_service_byte_results"; + public static final String TEXT_EMBEDDING_BYTES = "text_embedding_bytes"; + + public TextEmbeddingByteResults(StreamInput in) throws IOException { + this(in.readCollectionAsList(TextEmbeddingByteResults.Embedding::new)); + } + + @Override + public int getFirstEmbeddingSize() { + if (embeddings.isEmpty()) { + throw new IllegalStateException("Embeddings list is empty"); + } + return embeddings.getFirst().values().length; + } + + @Override + public Iterator toXContentChunked(ToXContent.Params params) { + return ChunkedToXContentHelper.array(TEXT_EMBEDDING_BYTES, embeddings.iterator()); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeCollection(embeddings); + } + + @Override + public String getWriteableName() { + return NAME; + } + + @Override + public List transformToCoordinationFormat() { + return embeddings.stream() + .map(embedding -> new MlTextEmbeddingResults(TEXT_EMBEDDING_BYTES, embedding.toDoubleArray(), false)) + .toList(); + } + + @Override + @SuppressWarnings("deprecation") + public List transformToLegacyFormat() { + var legacyEmbedding = new LegacyTextEmbeddingResults( + embeddings.stream().map(embedding -> new LegacyTextEmbeddingResults.Embedding(embedding.toFloatArray())).toList() + ); + + return List.of(legacyEmbedding); + } + + public Map asMap() { + Map map = new LinkedHashMap<>(); + map.put(TEXT_EMBEDDING_BYTES, embeddings); + + return map; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + TextEmbeddingByteResults that = (TextEmbeddingByteResults) o; + return Objects.equals(embeddings, that.embeddings); + } + + @Override + public int hashCode() { + return Objects.hash(embeddings); + } + + public record Embedding(byte[] values) implements Writeable, ToXContentObject, EmbeddingResults.Embedding { + public static final String EMBEDDING = "embedding"; + + public Embedding(StreamInput in) throws IOException { + this(in.readByteArray()); + } + + @Override + public void writeTo(StreamOutput out) throws IOException { + out.writeByteArray(values); + } + + public static Embedding of(List embeddingValuesList) { + byte[] embeddingValues = new byte[embeddingValuesList.size()]; + for (int i = 0; i < embeddingValuesList.size(); i++) { + embeddingValues[i] = embeddingValuesList.get(i); + } + return new Embedding(embeddingValues); + } + + @Override + public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { + builder.startObject(); + + builder.startArray(EMBEDDING); + for (byte value : values) { + builder.value(value); + } + builder.endArray(); + + builder.endObject(); + return builder; + } + + @Override + public String toString() { + return Strings.toString(this); + } + + float[] toFloatArray() { + float[] floatArray = new float[values.length]; + for (int i = 0; i < values.length; i++) { + floatArray[i] = ((Byte) values[i]).floatValue(); + } + return floatArray; + } + + double[] toDoubleArray() { + double[] doubleArray = new double[values.length]; + for (int i = 0; i < values.length; i++) { + doubleArray[i] = ((Byte) values[i]).doubleValue(); + } + return doubleArray; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Embedding embedding = (Embedding) o; + return Arrays.equals(values, embedding.values); + } + + @Override + public int hashCode() { + return Arrays.hashCode(values); + } + + @Override + public Chunk toChunk(String text, ChunkedInference.TextOffset offset) { + return new Chunk(values, text, offset); + } + } + + /** + * Serialises the {@code value} array, according to the provided {@link XContent}, into a {@link BytesReference}. + */ + public record Chunk(byte[] embedding, String matchedText, ChunkedInference.TextOffset offset) implements EmbeddingResults.Chunk { + + public ChunkedInference.Chunk toChunk(XContent xcontent) throws IOException { + return new ChunkedInference.Chunk(matchedText, offset, toBytesReference(xcontent, embedding)); + } + + private static BytesReference toBytesReference(XContent xContent, byte[] value) throws IOException { + XContentBuilder builder = XContentBuilder.builder(xContent); + builder.startArray(); + for (byte v : value) { + builder.value(v); + } + builder.endArray(); + return BytesReference.bytes(builder); + } + } +} diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceTextEmbeddingFloatResults.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingFloatResults.java similarity index 70% rename from x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceTextEmbeddingFloatResults.java rename to x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingFloatResults.java index 9f9bdfec7cfa..cef381982b44 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/InferenceTextEmbeddingFloatResults.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingFloatResults.java @@ -11,16 +11,18 @@ package org.elasticsearch.xpack.core.inference.results; import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.common.Strings; +import org.elasticsearch.common.bytes.BytesReference; 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.xcontent.ChunkedToXContentHelper; +import org.elasticsearch.inference.ChunkedInference; import org.elasticsearch.inference.InferenceResults; -import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.inference.TaskType; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.ToXContentObject; +import org.elasticsearch.xcontent.XContent; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xpack.core.ml.inference.results.MlTextEmbeddingResults; @@ -51,32 +53,31 @@ import java.util.stream.Collectors; * ] * } */ -public record InferenceTextEmbeddingFloatResults(List embeddings) +public record TextEmbeddingFloatResults(List embeddings) implements - InferenceServiceResults, - TextEmbedding { + TextEmbeddingResults { public static final String NAME = "text_embedding_service_results"; public static final String TEXT_EMBEDDING = TaskType.TEXT_EMBEDDING.toString(); - public InferenceTextEmbeddingFloatResults(StreamInput in) throws IOException { - this(in.readCollectionAsList(InferenceFloatEmbedding::new)); + public TextEmbeddingFloatResults(StreamInput in) throws IOException { + this(in.readCollectionAsList(TextEmbeddingFloatResults.Embedding::new)); } @SuppressWarnings("deprecation") - InferenceTextEmbeddingFloatResults(LegacyTextEmbeddingResults legacyTextEmbeddingResults) { + TextEmbeddingFloatResults(LegacyTextEmbeddingResults legacyTextEmbeddingResults) { this( legacyTextEmbeddingResults.embeddings() .stream() - .map(embedding -> new InferenceFloatEmbedding(embedding.values())) + .map(embedding -> new Embedding(embedding.values())) .collect(Collectors.toList()) ); } - public static InferenceTextEmbeddingFloatResults of(List results) { - List embeddings = new ArrayList<>(results.size()); + public static TextEmbeddingFloatResults of(List results) { + List embeddings = new ArrayList<>(results.size()); for (InferenceResults result : results) { if (result instanceof MlTextEmbeddingResults embeddingResult) { - embeddings.add(InferenceFloatEmbedding.of(embeddingResult)); + embeddings.add(TextEmbeddingFloatResults.Embedding.of(embeddingResult)); } else if (result instanceof org.elasticsearch.xpack.core.ml.inference.results.ErrorInferenceResults errorResult) { if (errorResult.getException() instanceof ElasticsearchStatusException statusException) { throw statusException; @@ -93,12 +94,15 @@ public record InferenceTextEmbeddingFloatResults(List e ); } } - return new InferenceTextEmbeddingFloatResults(embeddings); + return new TextEmbeddingFloatResults(embeddings); } @Override public int getFirstEmbeddingSize() { - return TextEmbeddingUtils.getFirstEmbeddingSize(new ArrayList<>(embeddings)); + if (embeddings.isEmpty()) { + throw new IllegalStateException("Embeddings list is empty"); + } + return embeddings.getFirst().values().length; } @Override @@ -142,7 +146,7 @@ public record InferenceTextEmbeddingFloatResults(List e public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - InferenceTextEmbeddingFloatResults that = (InferenceTextEmbeddingFloatResults) o; + TextEmbeddingFloatResults that = (TextEmbeddingFloatResults) o; return Objects.equals(embeddings, that.embeddings); } @@ -151,29 +155,24 @@ public record InferenceTextEmbeddingFloatResults(List e return Objects.hash(embeddings); } - public record InferenceFloatEmbedding(float[] values) implements Writeable, ToXContentObject, EmbeddingInt { + public record Embedding(float[] values) implements Writeable, ToXContentObject, EmbeddingResults.Embedding { public static final String EMBEDDING = "embedding"; - public InferenceFloatEmbedding(StreamInput in) throws IOException { + public Embedding(StreamInput in) throws IOException { this(in.readFloatArray()); } - public static InferenceFloatEmbedding of(MlTextEmbeddingResults embeddingResult) { + public static Embedding of(MlTextEmbeddingResults embeddingResult) { float[] embeddingAsArray = embeddingResult.getInferenceAsFloat(); - return new InferenceFloatEmbedding(embeddingAsArray); + return new Embedding(embeddingAsArray); } - public static InferenceFloatEmbedding of(List embeddingValuesList) { + public static Embedding of(List embeddingValuesList) { float[] embeddingValues = new float[embeddingValuesList.size()]; for (int i = 0; i < embeddingValuesList.size(); i++) { embeddingValues[i] = embeddingValuesList.get(i); } - return new InferenceFloatEmbedding(embeddingValues); - } - - @Override - public int getSize() { - return values.length; + return new Embedding(embeddingValues); } @Override @@ -212,7 +211,7 @@ public record InferenceTextEmbeddingFloatResults(List e public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - InferenceFloatEmbedding embedding = (InferenceFloatEmbedding) o; + Embedding embedding = (Embedding) o; return Arrays.equals(values, embedding.values); } @@ -220,5 +219,30 @@ public record InferenceTextEmbeddingFloatResults(List e public int hashCode() { return Arrays.hashCode(values); } + + @Override + public Chunk toChunk(String text, ChunkedInference.TextOffset offset) { + return new Chunk(values, text, offset); + } + } + + public record Chunk(float[] embedding, String matchedText, ChunkedInference.TextOffset offset) implements EmbeddingResults.Chunk { + + public ChunkedInference.Chunk toChunk(XContent xcontent) throws IOException { + return new ChunkedInference.Chunk(matchedText, offset, toBytesReference(xcontent, embedding)); + } + + /** + * Serialises the {@code value} array, according to the provided {@link XContent}, into a {@link BytesReference}. + */ + private static BytesReference toBytesReference(XContent xContent, float[] value) throws IOException { + XContentBuilder b = XContentBuilder.builder(xContent); + b.startArray(); + for (float v : value) { + b.value(v); + } + b.endArray(); + return BytesReference.bytes(b); + } } } diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbedding.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingResults.java similarity index 78% rename from x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbedding.java rename to x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingResults.java index a185c2938223..4caeea4930fd 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbedding.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingResults.java @@ -7,7 +7,9 @@ package org.elasticsearch.xpack.core.inference.results; -public interface TextEmbedding { +public interface TextEmbeddingResults> + extends + EmbeddingResults { /** * Returns the first text embedding entry in the result list's array size. diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingUtils.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingUtils.java index cb69f1e403e9..0ba8102b1dab 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingUtils.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/inference/results/TextEmbeddingUtils.java @@ -13,20 +13,6 @@ import java.util.List; public class TextEmbeddingUtils { - /** - * Returns the first text embedding entry's array size. - * @param embeddings the list of embeddings - * @return the size of the text embedding - * @throws IllegalStateException if the list of embeddings is empty - */ - public static int getFirstEmbeddingSize(List embeddings) throws IllegalStateException { - if (embeddings.isEmpty()) { - throw new IllegalStateException("Embeddings list is empty"); - } - - return embeddings.get(0).getSize(); - } - /** * Throws an exception if the number of elements in the input text list is different than the results in text embedding * response. diff --git a/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestDenseInferenceServiceExtension.java b/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestDenseInferenceServiceExtension.java index 1f17e335462a..da7acf122bb7 100644 --- a/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestDenseInferenceServiceExtension.java +++ b/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestDenseInferenceServiceExtension.java @@ -34,8 +34,8 @@ import org.elasticsearch.inference.configuration.SettingsConfigurationFieldType; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import java.io.IOException; import java.nio.charset.StandardCharsets; @@ -164,24 +164,24 @@ public class TestDenseInferenceServiceExtension implements InferenceServiceExten } } - private InferenceTextEmbeddingFloatResults makeResults(List input, int dimensions) { - List embeddings = new ArrayList<>(); + private TextEmbeddingFloatResults makeResults(List input, int dimensions) { + List embeddings = new ArrayList<>(); for (String inputString : input) { List floatEmbeddings = generateEmbedding(inputString, dimensions); - embeddings.add(InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(floatEmbeddings)); + embeddings.add(TextEmbeddingFloatResults.Embedding.of(floatEmbeddings)); } - return new InferenceTextEmbeddingFloatResults(embeddings); + return new TextEmbeddingFloatResults(embeddings); } private List makeChunkedResults(List input, int dimensions) { - InferenceTextEmbeddingFloatResults nonChunkedResults = makeResults(input, dimensions); + TextEmbeddingFloatResults nonChunkedResults = makeResults(input, dimensions); var results = new ArrayList(); for (int i = 0; i < input.size(); i++) { results.add( - new ChunkedInferenceEmbeddingFloat( + new ChunkedInferenceEmbedding( List.of( - new ChunkedInferenceEmbeddingFloat.FloatEmbeddingChunk( + new TextEmbeddingFloatResults.Chunk( nonChunkedResults.embeddings().get(i).values(), input.get(i), new ChunkedInference.TextOffset(0, input.get(i).length()) diff --git a/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestSparseInferenceServiceExtension.java b/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestSparseInferenceServiceExtension.java index f700f6672fd6..fcc175a05196 100644 --- a/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestSparseInferenceServiceExtension.java +++ b/x-pack/plugin/inference/qa/test-service-plugin/src/main/java/org/elasticsearch/xpack/inference/mock/TestSparseInferenceServiceExtension.java @@ -32,7 +32,7 @@ import org.elasticsearch.inference.configuration.SettingsConfigurationFieldType; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.xcontent.ToXContentObject; import org.elasticsearch.xcontent.XContentBuilder; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; import org.elasticsearch.xpack.core.ml.search.WeightedToken; @@ -171,9 +171,9 @@ public class TestSparseInferenceServiceExtension implements InferenceServiceExte tokens.add(new WeightedToken("feature_" + j, generateEmbedding(input.get(i), j))); } results.add( - new ChunkedInferenceEmbeddingSparse( + new ChunkedInferenceEmbedding( List.of( - new ChunkedInferenceEmbeddingSparse.SparseEmbeddingChunk( + new SparseEmbeddingResults.Chunk( tokens, input.get(i), new ChunkedInference.TextOffset(0, input.get(i).length()) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceNamedWriteablesProvider.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceNamedWriteablesProvider.java index ef79452e94c7..35d2ce075c44 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceNamedWriteablesProvider.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceNamedWriteablesProvider.java @@ -18,13 +18,13 @@ import org.elasticsearch.inference.ServiceSettings; import org.elasticsearch.inference.TaskSettings; import org.elasticsearch.inference.UnifiedCompletionRequest; import org.elasticsearch.xpack.core.inference.results.ChatCompletionResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingByteResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; import org.elasticsearch.xpack.core.inference.results.LegacyTextEmbeddingResults; import org.elasticsearch.xpack.core.inference.results.RankedDocsResults; import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; import org.elasticsearch.xpack.core.inference.results.StreamingChatCompletionResults; import org.elasticsearch.xpack.core.inference.results.StreamingUnifiedChatCompletionResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.action.task.StreamingTaskManager; import org.elasticsearch.xpack.inference.chunking.SentenceBoundaryChunkingSettings; import org.elasticsearch.xpack.inference.chunking.WordBoundaryChunkingSettings; @@ -473,18 +473,10 @@ public class InferenceNamedWriteablesProvider { new NamedWriteableRegistry.Entry(InferenceServiceResults.class, SparseEmbeddingResults.NAME, SparseEmbeddingResults::new) ); namedWriteables.add( - new NamedWriteableRegistry.Entry( - InferenceServiceResults.class, - InferenceTextEmbeddingFloatResults.NAME, - InferenceTextEmbeddingFloatResults::new - ) + new NamedWriteableRegistry.Entry(InferenceServiceResults.class, TextEmbeddingFloatResults.NAME, TextEmbeddingFloatResults::new) ); namedWriteables.add( - new NamedWriteableRegistry.Entry( - InferenceServiceResults.class, - InferenceTextEmbeddingByteResults.NAME, - InferenceTextEmbeddingByteResults::new - ) + new NamedWriteableRegistry.Entry(InferenceServiceResults.class, TextEmbeddingByteResults.NAME, TextEmbeddingByteResults::new) ); namedWriteables.add( new NamedWriteableRegistry.Entry(InferenceServiceResults.class, ChatCompletionResults.NAME, ChatCompletionResults::new) diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/EmbeddingRequestChunker.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/EmbeddingRequestChunker.java index fb796c2afdfe..d8751a542392 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/EmbeddingRequestChunker.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/chunking/EmbeddingRequestChunker.java @@ -10,24 +10,19 @@ package org.elasticsearch.xpack.inference.chunking; import org.elasticsearch.ElasticsearchStatusException; import org.elasticsearch.action.ActionListener; import org.elasticsearch.common.util.concurrent.AtomicArray; -import org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapper; import org.elasticsearch.inference.ChunkedInference; import org.elasticsearch.inference.ChunkingSettings; import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.rest.RestStatus; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingByte; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceError; -import org.elasticsearch.xpack.core.inference.results.InferenceByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingByteResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; -import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; +import org.elasticsearch.xpack.core.inference.results.EmbeddingResults; +import org.elasticsearch.xpack.inference.chunking.Chunker.ChunkOffset; import java.util.ArrayList; import java.util.List; import java.util.concurrent.atomic.AtomicInteger; -import java.util.function.Function; +import java.util.concurrent.atomic.AtomicReferenceArray; import java.util.stream.Collectors; /** @@ -43,145 +38,72 @@ import java.util.stream.Collectors; */ public class EmbeddingRequestChunker { - public enum EmbeddingType { - FLOAT, - BYTE, - SPARSE; - - public static EmbeddingType fromDenseVectorElementType(DenseVectorFieldMapper.ElementType elementType) { - return switch (elementType) { - case BYTE -> EmbeddingType.BYTE; - case FLOAT -> EmbeddingType.FLOAT; - case BIT -> throw new IllegalArgumentException("Bit vectors are not supported"); - }; + // Visible for testing + record Request(int inputIndex, int chunkIndex, ChunkOffset chunk, List inputs) { + public String chunkText() { + return inputs.get(inputIndex).substring(chunk.start(), chunk.end()); } - }; + } - public static final int DEFAULT_WORDS_PER_CHUNK = 250; - public static final int DEFAULT_CHUNK_OVERLAP = 100; + public record BatchRequest(List requests) { + public List inputs() { + return requests.stream().map(Request::chunkText).collect(Collectors.toList()); + } + } - private final List batchedRequests = new ArrayList<>(); + public record BatchRequestAndListener(BatchRequest batch, ActionListener listener) {} + + private static final int DEFAULT_WORDS_PER_CHUNK = 250; + private static final int DEFAULT_CHUNK_OVERLAP = 100; + + private final List inputs; + private final List> requests; + private final List batchRequests; private final AtomicInteger resultCount = new AtomicInteger(); - private final int maxNumberOfInputsPerBatch; - private final int wordsPerChunk; - private final int chunkOverlap; - private final EmbeddingType embeddingType; - private final ChunkingSettings chunkingSettings; - private List chunkedOffsets; - private List>> floatResults; - private List>> byteResults; - private List>> sparseResults; - private AtomicArray errors; + private final List>> results; + private final AtomicArray errors; private ActionListener> finalListener; - public EmbeddingRequestChunker(List inputs, int maxNumberOfInputsPerBatch, EmbeddingType embeddingType) { - this(inputs, maxNumberOfInputsPerBatch, DEFAULT_WORDS_PER_CHUNK, DEFAULT_CHUNK_OVERLAP, embeddingType); + public EmbeddingRequestChunker(List inputs, int maxNumberOfInputsPerBatch) { + this(inputs, maxNumberOfInputsPerBatch, null); } - public EmbeddingRequestChunker( - List inputs, - int maxNumberOfInputsPerBatch, - int wordsPerChunk, - int chunkOverlap, - EmbeddingType embeddingType - ) { - this.maxNumberOfInputsPerBatch = maxNumberOfInputsPerBatch; - this.wordsPerChunk = wordsPerChunk; - this.chunkOverlap = chunkOverlap; - this.embeddingType = embeddingType; - this.chunkingSettings = null; - splitIntoBatchedRequests(inputs); + public EmbeddingRequestChunker(List inputs, int maxNumberOfInputsPerBatch, int wordsPerChunk, int chunkOverlap) { + this(inputs, maxNumberOfInputsPerBatch, new WordBoundaryChunkingSettings(wordsPerChunk, chunkOverlap)); } - public EmbeddingRequestChunker( - List inputs, - int maxNumberOfInputsPerBatch, - EmbeddingType embeddingType, - ChunkingSettings chunkingSettings - ) { - this.maxNumberOfInputsPerBatch = maxNumberOfInputsPerBatch; - this.wordsPerChunk = DEFAULT_WORDS_PER_CHUNK; // Can be removed after ChunkingConfigurationFeatureFlag is enabled - this.chunkOverlap = DEFAULT_CHUNK_OVERLAP; // Can be removed after ChunkingConfigurationFeatureFlag is enabled - this.embeddingType = embeddingType; - this.chunkingSettings = chunkingSettings; - splitIntoBatchedRequests(inputs); - } + public EmbeddingRequestChunker(List inputs, int maxNumberOfInputsPerBatch, ChunkingSettings chunkingSettings) { + this.inputs = inputs; + this.results = new ArrayList<>(inputs.size()); + this.errors = new AtomicArray<>(inputs.size()); - private void splitIntoBatchedRequests(List inputs) { - Function> chunkFunction; - if (chunkingSettings != null) { - var chunker = ChunkerBuilder.fromChunkingStrategy(chunkingSettings.getChunkingStrategy()); - chunkFunction = input -> chunker.chunk(input, chunkingSettings); - } else { - var chunker = new WordBoundaryChunker(); - chunkFunction = input -> chunker.chunk(input, wordsPerChunk, chunkOverlap); + if (chunkingSettings == null) { + chunkingSettings = new WordBoundaryChunkingSettings(DEFAULT_WORDS_PER_CHUNK, DEFAULT_CHUNK_OVERLAP); } + Chunker chunker = ChunkerBuilder.fromChunkingStrategy(chunkingSettings.getChunkingStrategy()); - chunkedOffsets = new ArrayList<>(inputs.size()); - switch (embeddingType) { - case FLOAT -> floatResults = new ArrayList<>(inputs.size()); - case BYTE -> byteResults = new ArrayList<>(inputs.size()); - case SPARSE -> sparseResults = new ArrayList<>(inputs.size()); - } - errors = new AtomicArray<>(inputs.size()); + this.requests = new ArrayList<>(inputs.size()); - for (int i = 0; i < inputs.size(); i++) { - var chunks = chunkFunction.apply(inputs.get(i)); - var offSetsAndInput = new ChunkOffsetsAndInput(chunks, inputs.get(i)); - int numberOfSubBatches = addToBatches(offSetsAndInput, i); - // size the results array with the expected number of request/responses - switch (embeddingType) { - case FLOAT -> floatResults.add(new AtomicArray<>(numberOfSubBatches)); - case BYTE -> byteResults.add(new AtomicArray<>(numberOfSubBatches)); - case SPARSE -> sparseResults.add(new AtomicArray<>(numberOfSubBatches)); + for (int inputIndex = 0; inputIndex < inputs.size(); inputIndex++) { + List chunks = chunker.chunk(inputs.get(inputIndex), chunkingSettings); + List requestForInput = new ArrayList<>(chunks.size()); + for (int chunkIndex = 0; chunkIndex < chunks.size(); chunkIndex++) { + requestForInput.add(new Request(inputIndex, chunkIndex, chunks.get(chunkIndex), inputs)); } - chunkedOffsets.add(offSetsAndInput); - } - } - - private int addToBatches(ChunkOffsetsAndInput chunk, int inputIndex) { - BatchRequest lastBatch; - if (batchedRequests.isEmpty()) { - lastBatch = new BatchRequest(new ArrayList<>()); - batchedRequests.add(lastBatch); - } else { - lastBatch = batchedRequests.get(batchedRequests.size() - 1); + requests.add(requestForInput); + // size the results array with the expected number of request/responses + results.add(new AtomicReferenceArray<>(chunks.size())); } - int freeSpace = maxNumberOfInputsPerBatch - lastBatch.size(); - assert freeSpace >= 0; - - // chunks may span multiple batches, - // the chunkIndex keeps them ordered. - int chunkIndex = 0; - - if (freeSpace > 0) { - // use any free space in the previous batch before creating new batches - int toAdd = Math.min(freeSpace, chunk.offsets().size()); - lastBatch.addSubBatch( - new SubBatch( - new ChunkOffsetsAndInput(chunk.offsets().subList(0, toAdd), chunk.input()), - new SubBatchPositionsAndCount(inputIndex, chunkIndex++, toAdd) - ) - ); - } - - int start = freeSpace; - while (start < chunk.offsets().size()) { - int toAdd = Math.min(maxNumberOfInputsPerBatch, chunk.offsets().size() - start); - var batch = new BatchRequest(new ArrayList<>()); - batch.addSubBatch( - new SubBatch( - new ChunkOffsetsAndInput(chunk.offsets().subList(start, start + toAdd), chunk.input()), - new SubBatchPositionsAndCount(inputIndex, chunkIndex++, toAdd) - ) - ); - batchedRequests.add(batch); - start += toAdd; - } - - return chunkIndex; + AtomicInteger counter = new AtomicInteger(); + this.batchRequests = requests.stream() + .flatMap(List::stream) + .collect(Collectors.groupingBy(it -> counter.getAndIncrement() / maxNumberOfInputsPerBatch)) + .values() + .stream() + .map(BatchRequest::new) + .toList(); } /** @@ -191,23 +113,7 @@ public class EmbeddingRequestChunker { */ public List batchRequestsWithListeners(ActionListener> finalListener) { this.finalListener = finalListener; - - int numberOfRequests = batchedRequests.size(); - - var requests = new ArrayList(numberOfRequests); - for (var batch : batchedRequests) { - requests.add( - new BatchRequestAndListener( - batch, - new DebatchingListener( - batch.subBatches().stream().map(SubBatch::positions).collect(Collectors.toList()), - numberOfRequests - ) - ) - ); - } - - return requests; + return batchRequests.stream().map(req -> new BatchRequestAndListener(req, new DebatchingListener(req))).toList(); } /** @@ -220,266 +126,83 @@ public class EmbeddingRequestChunker { */ private class DebatchingListener implements ActionListener { - private final List positions; - private final int totalNumberOfRequests; + private final BatchRequest request; - DebatchingListener(List positions, int totalNumberOfRequests) { - this.positions = positions; - this.totalNumberOfRequests = totalNumberOfRequests; + DebatchingListener(BatchRequest request) { + this.request = request; } @Override public void onResponse(InferenceServiceResults inferenceServiceResults) { - switch (embeddingType) { - case FLOAT -> handleFloatResults(inferenceServiceResults); - case BYTE -> handleByteResults(inferenceServiceResults); - case SPARSE -> handleSparseResults(inferenceServiceResults); - } - } - - private void handleFloatResults(InferenceServiceResults inferenceServiceResults) { - if (inferenceServiceResults instanceof InferenceTextEmbeddingFloatResults floatEmbeddings) { - if (failIfNumRequestsDoNotMatch(floatEmbeddings.embeddings().size())) { + if (inferenceServiceResults instanceof EmbeddingResults embeddingResults) { + if (embeddingResults.embeddings().size() != request.requests.size()) { + onFailure(numResultsDoesntMatchException(embeddingResults.embeddings().size(), request.requests.size())); return; } - - int start = 0; - for (var pos : positions) { - floatResults.get(pos.inputIndex()) - .setOnce(pos.chunkIndex(), floatEmbeddings.embeddings().subList(start, start + pos.embeddingCount())); - start += pos.embeddingCount(); + for (int i = 0; i < embeddingResults.embeddings().size(); i++) { + results.get(request.requests().get(i).inputIndex()) + .set(request.requests().get(i).chunkIndex(), embeddingResults.embeddings().get(i)); } - - if (resultCount.incrementAndGet() == totalNumberOfRequests) { - sendResponse(); + if (resultCount.incrementAndGet() == batchRequests.size()) { + sendFinalResponse(); } } else { - onFailure( - unexpectedResultTypeException(inferenceServiceResults.getWriteableName(), InferenceTextEmbeddingFloatResults.NAME) - ); + onFailure(unexpectedResultTypeException(inferenceServiceResults.getWriteableName())); } } - private void handleByteResults(InferenceServiceResults inferenceServiceResults) { - if (inferenceServiceResults instanceof InferenceTextEmbeddingByteResults byteEmbeddings) { - if (failIfNumRequestsDoNotMatch(byteEmbeddings.embeddings().size())) { - return; - } - - int start = 0; - for (var pos : positions) { - byteResults.get(pos.inputIndex()) - .setOnce(pos.chunkIndex(), byteEmbeddings.embeddings().subList(start, start + pos.embeddingCount())); - start += pos.embeddingCount(); - } - - if (resultCount.incrementAndGet() == totalNumberOfRequests) { - sendResponse(); - } - } else { - onFailure( - unexpectedResultTypeException(inferenceServiceResults.getWriteableName(), InferenceTextEmbeddingByteResults.NAME) - ); - } - } - - private void handleSparseResults(InferenceServiceResults inferenceServiceResults) { - if (inferenceServiceResults instanceof SparseEmbeddingResults sparseEmbeddings) { - if (failIfNumRequestsDoNotMatch(sparseEmbeddings.embeddings().size())) { - return; - } - - int start = 0; - for (var pos : positions) { - sparseResults.get(pos.inputIndex()) - .setOnce(pos.chunkIndex(), sparseEmbeddings.embeddings().subList(start, start + pos.embeddingCount())); - start += pos.embeddingCount(); - } - - if (resultCount.incrementAndGet() == totalNumberOfRequests) { - sendResponse(); - } - } else { - onFailure( - unexpectedResultTypeException(inferenceServiceResults.getWriteableName(), InferenceTextEmbeddingByteResults.NAME) - ); - } - } - - private boolean failIfNumRequestsDoNotMatch(int numberOfResults) { - int numberOfRequests = positions.stream().mapToInt(SubBatchPositionsAndCount::embeddingCount).sum(); - if (numberOfRequests != numberOfResults) { - onFailure( - new ElasticsearchStatusException( - "Error the number of embedding responses [{}] does not equal the number of " + "requests [{}]", - RestStatus.INTERNAL_SERVER_ERROR, - numberOfResults, - numberOfRequests - ) - ); - return true; - } - return false; - } - - private ElasticsearchStatusException unexpectedResultTypeException(String got, String expected) { + private ElasticsearchStatusException numResultsDoesntMatchException(int numResults, int numRequests) { return new ElasticsearchStatusException( - "Unexpected inference result type [" + got + "], expected a [" + expected + "]", - RestStatus.INTERNAL_SERVER_ERROR + "Error the number of embedding responses [{}] does not equal the number of requests [{}]", + RestStatus.INTERNAL_SERVER_ERROR, + numResults, + numRequests + ); + } + + private ElasticsearchStatusException unexpectedResultTypeException(String resultType) { + return new ElasticsearchStatusException( + "Unexpected inference result type [{}], expected [EmbeddingResults]", + RestStatus.INTERNAL_SERVER_ERROR, + resultType ); } @Override public void onFailure(Exception e) { - for (var pos : positions) { - errors.set(pos.inputIndex(), e); + for (Request request : request.requests) { + errors.set(request.inputIndex(), e); } - - if (resultCount.incrementAndGet() == totalNumberOfRequests) { - sendResponse(); + if (resultCount.incrementAndGet() == batchRequests.size()) { + sendFinalResponse(); } } + } - private void sendResponse() { - var response = new ArrayList(chunkedOffsets.size()); - for (int i = 0; i < chunkedOffsets.size(); i++) { - if (errors.get(i) != null) { - response.add(new ChunkedInferenceError(errors.get(i))); - } else { - response.add(mergeResultsWithInputs(i)); - } + private void sendFinalResponse() { + var response = new ArrayList(inputs.size()); + for (int i = 0; i < inputs.size(); i++) { + if (errors.get(i) != null) { + response.add(new ChunkedInferenceError(errors.get(i))); + } else { + response.add(mergeResultsWithInputs(i)); } - - finalListener.onResponse(response); } + finalListener.onResponse(response); } - private ChunkedInference mergeResultsWithInputs(int resultIndex) { - return switch (embeddingType) { - case FLOAT -> mergeFloatResultsWithInputs(chunkedOffsets.get(resultIndex), floatResults.get(resultIndex)); - case BYTE -> mergeByteResultsWithInputs(chunkedOffsets.get(resultIndex), byteResults.get(resultIndex)); - case SPARSE -> mergeSparseResultsWithInputs(chunkedOffsets.get(resultIndex), sparseResults.get(resultIndex)); - }; - } - - private ChunkedInferenceEmbeddingFloat mergeFloatResultsWithInputs( - ChunkOffsetsAndInput chunks, - AtomicArray> debatchedResults - ) { - var all = new ArrayList(); - for (int i = 0; i < debatchedResults.length(); i++) { - var subBatch = debatchedResults.get(i); - all.addAll(subBatch); - } - - assert chunks.size() == all.size(); - - var embeddingChunks = new ArrayList(); - for (int i = 0; i < chunks.size(); i++) { - embeddingChunks.add( - new ChunkedInferenceEmbeddingFloat.FloatEmbeddingChunk( - all.get(i).values(), - chunks.chunkText(i), - new ChunkedInference.TextOffset(chunks.offsets().get(i).start(), chunks.offsets().get(i).end()) - ) - ); - } - - return new ChunkedInferenceEmbeddingFloat(embeddingChunks); - } - - private ChunkedInferenceEmbeddingByte mergeByteResultsWithInputs( - ChunkOffsetsAndInput chunks, - AtomicArray> debatchedResults - ) { - var all = new ArrayList(); - for (int i = 0; i < debatchedResults.length(); i++) { - var subBatch = debatchedResults.get(i); - all.addAll(subBatch); - } - - assert chunks.size() == all.size(); - - var embeddingChunks = new ArrayList(); - for (int i = 0; i < chunks.size(); i++) { - embeddingChunks.add( - new ChunkedInferenceEmbeddingByte.ByteEmbeddingChunk( - all.get(i).values(), - chunks.chunkText(i), - new ChunkedInference.TextOffset(chunks.offsets().get(i).start(), chunks.offsets().get(i).end()) - ) - ); - } - - return new ChunkedInferenceEmbeddingByte(embeddingChunks); - } - - private ChunkedInferenceEmbeddingSparse mergeSparseResultsWithInputs( - ChunkOffsetsAndInput chunks, - AtomicArray> debatchedResults - ) { - var all = new ArrayList(); - for (int i = 0; i < debatchedResults.length(); i++) { - var subBatch = debatchedResults.get(i); - all.addAll(subBatch); - } - - assert chunks.size() == all.size(); - - var embeddingChunks = new ArrayList(); - for (int i = 0; i < chunks.size(); i++) { - embeddingChunks.add( - new ChunkedInferenceEmbeddingSparse.SparseEmbeddingChunk( - all.get(i).tokens(), - chunks.chunkText(i), - new ChunkedInference.TextOffset(chunks.offsets().get(i).start(), chunks.offsets().get(i).end()) - ) - ); - } - - return new ChunkedInferenceEmbeddingSparse(embeddingChunks); - } - - public record BatchRequest(List subBatches) { - public int size() { - return subBatches.stream().mapToInt(SubBatch::size).sum(); - } - - public void addSubBatch(SubBatch sb) { - subBatches.add(sb); - } - - public List inputs() { - return subBatches.stream().flatMap(s -> s.requests().toChunkText().stream()).collect(Collectors.toList()); - } - } - - public record BatchRequestAndListener(BatchRequest batch, ActionListener listener) { - - } - - /** - * Used for mapping batched requests back to the original input - */ - record SubBatchPositionsAndCount(int inputIndex, int chunkIndex, int embeddingCount) {} - - record SubBatch(ChunkOffsetsAndInput requests, SubBatchPositionsAndCount positions) { - int size() { - return requests.offsets().size(); - } - } - - record ChunkOffsetsAndInput(List offsets, String input) { - List toChunkText() { - return offsets.stream().map(o -> input.substring(o.start(), o.end())).collect(Collectors.toList()); - } - - int size() { - return offsets.size(); - } - - String chunkText(int index) { - return input.substring(offsets.get(index).start(), offsets.get(index).end()); + private ChunkedInference mergeResultsWithInputs(int index) { + List chunks = new ArrayList<>(); + List request = requests.get(index); + AtomicReferenceArray> result = results.get(index); + for (int i = 0; i < request.size(); i++) { + EmbeddingResults.Chunk chunk = result.get(i) + .toChunk( + request.get(i).chunkText(), + new ChunkedInference.TextOffset(request.get(i).chunk.start(), request.get(i).chunk.end()) + ); + chunks.add(chunk); } + return new ChunkedInferenceEmbedding(chunks); } } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/alibabacloudsearch/AlibabaCloudSearchEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/alibabacloudsearch/AlibabaCloudSearchEmbeddingsResponseEntity.java index 33fa645b107b..554ab655def6 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/alibabacloudsearch/AlibabaCloudSearchEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/alibabacloudsearch/AlibabaCloudSearchEmbeddingsResponseEntity.java @@ -9,7 +9,7 @@ package org.elasticsearch.xpack.inference.external.response.alibabacloudsearch; import org.elasticsearch.common.xcontent.XContentParserUtils; import org.elasticsearch.xcontent.XContentParser; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -70,21 +70,20 @@ public class AlibabaCloudSearchEmbeddingsResponseEntity extends AlibabaCloudSear * * */ - public static InferenceTextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { + public static TextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { return fromResponse(request, response, parser -> { positionParserAtTokenAfterField(parser, "embeddings", FAILED_TO_FIND_FIELD_TEMPLATE); - List embeddingList = XContentParserUtils.parseList( + List embeddingList = XContentParserUtils.parseList( parser, AlibabaCloudSearchEmbeddingsResponseEntity::parseEmbeddingObject ); - return new InferenceTextEmbeddingFloatResults(embeddingList); + return new TextEmbeddingFloatResults(embeddingList); }); } - private static InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding parseEmbeddingObject(XContentParser parser) - throws IOException { + private static TextEmbeddingFloatResults.Embedding parseEmbeddingObject(XContentParser parser) throws IOException { XContentParserUtils.ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser); positionParserAtTokenAfterField(parser, "embedding", FAILED_TO_FIND_FIELD_TEMPLATE); @@ -96,7 +95,7 @@ public class AlibabaCloudSearchEmbeddingsResponseEntity extends AlibabaCloudSear // if there are additional fields within this object, lets skip them, so we can begin parsing the next embedding array parser.skipChildren(); - return InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(embeddingValues); + return TextEmbeddingFloatResults.Embedding.of(embeddingValues); } private static float parseEmbeddingList(XContentParser parser) throws IOException { diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/amazonbedrock/embeddings/AmazonBedrockEmbeddingsResponse.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/amazonbedrock/embeddings/AmazonBedrockEmbeddingsResponse.java index 1848e082dec4..017654ebb191 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/amazonbedrock/embeddings/AmazonBedrockEmbeddingsResponse.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/amazonbedrock/embeddings/AmazonBedrockEmbeddingsResponse.java @@ -16,7 +16,7 @@ import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.request.amazonbedrock.AmazonBedrockRequest; import org.elasticsearch.xpack.inference.external.request.amazonbedrock.embeddings.AmazonBedrockEmbeddingsRequest; import org.elasticsearch.xpack.inference.external.response.XContentUtils; @@ -48,7 +48,7 @@ public class AmazonBedrockEmbeddingsResponse extends AmazonBedrockResponse { throw new ElasticsearchException("unexpected request type [" + request.getClass() + "]"); } - public static InferenceTextEmbeddingFloatResults fromResponse(InvokeModelResponse response, AmazonBedrockProvider provider) { + public static TextEmbeddingFloatResults fromResponse(InvokeModelResponse response, AmazonBedrockProvider provider) { var charset = StandardCharsets.UTF_8; var bodyText = String.valueOf(charset.decode(response.body().asByteBuffer())); @@ -63,16 +63,14 @@ public class AmazonBedrockEmbeddingsResponse extends AmazonBedrockResponse { var embeddingList = parseEmbeddings(jsonParser, provider); - return new InferenceTextEmbeddingFloatResults(embeddingList); + return new TextEmbeddingFloatResults(embeddingList); } catch (IOException e) { throw new ElasticsearchException(e); } } - private static List parseEmbeddings( - XContentParser jsonParser, - AmazonBedrockProvider provider - ) throws IOException { + private static List parseEmbeddings(XContentParser jsonParser, AmazonBedrockProvider provider) + throws IOException { switch (provider) { case AMAZONTITAN -> { return parseTitanEmbeddings(jsonParser); @@ -84,8 +82,7 @@ public class AmazonBedrockEmbeddingsResponse extends AmazonBedrockResponse { } } - private static List parseTitanEmbeddings(XContentParser parser) - throws IOException { + private static List parseTitanEmbeddings(XContentParser parser) throws IOException { /* Titan response: { @@ -95,12 +92,11 @@ public class AmazonBedrockEmbeddingsResponse extends AmazonBedrockResponse { */ positionParserAtTokenAfterField(parser, "embedding", FAILED_TO_FIND_FIELD_TEMPLATE); List embeddingValuesList = parseList(parser, XContentUtils::parseFloat); - var embeddingValues = InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(embeddingValuesList); + var embeddingValues = TextEmbeddingFloatResults.Embedding.of(embeddingValuesList); return List.of(embeddingValues); } - private static List parseCohereEmbeddings(XContentParser parser) - throws IOException { + private static List parseCohereEmbeddings(XContentParser parser) throws IOException { /* Cohere response: { @@ -115,7 +111,7 @@ public class AmazonBedrockEmbeddingsResponse extends AmazonBedrockResponse { */ positionParserAtTokenAfterField(parser, "embeddings", FAILED_TO_FIND_FIELD_TEMPLATE); - List embeddingList = parseList( + List embeddingList = parseList( parser, AmazonBedrockEmbeddingsResponse::parseCohereEmbeddingsListItem ); @@ -123,10 +119,9 @@ public class AmazonBedrockEmbeddingsResponse extends AmazonBedrockResponse { return embeddingList; } - private static InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding parseCohereEmbeddingsListItem(XContentParser parser) - throws IOException { + private static TextEmbeddingFloatResults.Embedding parseCohereEmbeddingsListItem(XContentParser parser) throws IOException { List embeddingValuesList = parseList(parser, XContentUtils::parseFloat); - return InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(embeddingValuesList); + return TextEmbeddingFloatResults.Embedding.of(embeddingValuesList); } } diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntity.java index 2e574d477b05..cbd570e662b8 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntity.java @@ -17,10 +17,9 @@ import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.InferenceByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingBitResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingByteResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingBitResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; import org.elasticsearch.xpack.inference.external.response.XContentUtils; @@ -192,20 +191,20 @@ public class CohereEmbeddingsResponseEntity { // Cohere returns array of binary embeddings encoded as bytes with int8 precision so we can reuse the byte parser var embeddingList = parseList(parser, CohereEmbeddingsResponseEntity::parseByteArrayEntry); - return new InferenceTextEmbeddingBitResults(embeddingList); + return new TextEmbeddingBitResults(embeddingList); } private static InferenceServiceResults parseByteEmbeddingsArray(XContentParser parser) throws IOException { var embeddingList = parseList(parser, CohereEmbeddingsResponseEntity::parseByteArrayEntry); - return new InferenceTextEmbeddingByteResults(embeddingList); + return new TextEmbeddingByteResults(embeddingList); } - private static InferenceByteEmbedding parseByteArrayEntry(XContentParser parser) throws IOException { + private static TextEmbeddingByteResults.Embedding parseByteArrayEntry(XContentParser parser) throws IOException { ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.currentToken(), parser); List embeddingValuesList = parseList(parser, CohereEmbeddingsResponseEntity::parseEmbeddingInt8Entry); - return InferenceByteEmbedding.of(embeddingValuesList); + return TextEmbeddingByteResults.Embedding.of(embeddingValuesList); } private static Byte parseEmbeddingInt8Entry(XContentParser parser) throws IOException { @@ -226,14 +225,13 @@ public class CohereEmbeddingsResponseEntity { private static InferenceServiceResults parseFloatEmbeddingsArray(XContentParser parser) throws IOException { var embeddingList = parseList(parser, CohereEmbeddingsResponseEntity::parseFloatArrayEntry); - return new InferenceTextEmbeddingFloatResults(embeddingList); + return new TextEmbeddingFloatResults(embeddingList); } - private static InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding parseFloatArrayEntry(XContentParser parser) - throws IOException { + private static TextEmbeddingFloatResults.Embedding parseFloatArrayEntry(XContentParser parser) throws IOException { ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.currentToken(), parser); List embeddingValuesList = parseList(parser, XContentUtils::parseFloat); - return InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(embeddingValuesList); + return TextEmbeddingFloatResults.Embedding.of(embeddingValuesList); } private CohereEmbeddingsResponseEntity() {} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/googleaistudio/GoogleAiStudioEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/googleaistudio/GoogleAiStudioEmbeddingsResponseEntity.java index 543b8e39d85f..177241670dcc 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/googleaistudio/GoogleAiStudioEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/googleaistudio/GoogleAiStudioEmbeddingsResponseEntity.java @@ -12,7 +12,7 @@ import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; import org.elasticsearch.xpack.inference.external.response.XContentUtils; @@ -70,7 +70,7 @@ public class GoogleAiStudioEmbeddingsResponseEntity { * */ - public static InferenceTextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { + public static TextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { var parserConfig = XContentParserConfiguration.EMPTY.withDeprecationHandler(LoggingDeprecationHandler.INSTANCE); try (XContentParser jsonParser = XContentFactory.xContent(XContentType.JSON).createParser(parserConfig, response.body())) { @@ -81,17 +81,16 @@ public class GoogleAiStudioEmbeddingsResponseEntity { positionParserAtTokenAfterField(jsonParser, "embeddings", FAILED_TO_FIND_FIELD_TEMPLATE); - List embeddingList = parseList( + List embeddingList = parseList( jsonParser, GoogleAiStudioEmbeddingsResponseEntity::parseEmbeddingObject ); - return new InferenceTextEmbeddingFloatResults(embeddingList); + return new TextEmbeddingFloatResults(embeddingList); } } - private static InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding parseEmbeddingObject(XContentParser parser) - throws IOException { + private static TextEmbeddingFloatResults.Embedding parseEmbeddingObject(XContentParser parser) throws IOException { ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser); positionParserAtTokenAfterField(parser, "values", FAILED_TO_FIND_FIELD_TEMPLATE); @@ -100,7 +99,7 @@ public class GoogleAiStudioEmbeddingsResponseEntity { // parse and discard the rest of the object consumeUntilObjectEnd(parser); - return InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(embeddingValuesList); + return TextEmbeddingFloatResults.Embedding.of(embeddingValuesList); } private GoogleAiStudioEmbeddingsResponseEntity() {} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/googlevertexai/GoogleVertexAiEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/googlevertexai/GoogleVertexAiEmbeddingsResponseEntity.java index 7205ea83d0a7..631698eb121a 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/googlevertexai/GoogleVertexAiEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/googlevertexai/GoogleVertexAiEmbeddingsResponseEntity.java @@ -13,7 +13,7 @@ import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -64,7 +64,7 @@ public class GoogleVertexAiEmbeddingsResponseEntity { * */ - public static InferenceTextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { + public static TextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { var parserConfig = XContentParserConfiguration.EMPTY.withDeprecationHandler(LoggingDeprecationHandler.INSTANCE); try (XContentParser jsonParser = XContentFactory.xContent(XContentType.JSON).createParser(parserConfig, response.body())) { @@ -75,17 +75,16 @@ public class GoogleVertexAiEmbeddingsResponseEntity { positionParserAtTokenAfterField(jsonParser, "predictions", FAILED_TO_FIND_FIELD_TEMPLATE); - List embeddingList = parseList( + List embeddingList = parseList( jsonParser, GoogleVertexAiEmbeddingsResponseEntity::parseEmbeddingObject ); - return new InferenceTextEmbeddingFloatResults(embeddingList); + return new TextEmbeddingFloatResults(embeddingList); } } - private static InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding parseEmbeddingObject(XContentParser parser) - throws IOException { + private static TextEmbeddingFloatResults.Embedding parseEmbeddingObject(XContentParser parser) throws IOException { ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser); positionParserAtTokenAfterField(parser, "embeddings", FAILED_TO_FIND_FIELD_TEMPLATE); @@ -100,7 +99,7 @@ public class GoogleVertexAiEmbeddingsResponseEntity { consumeUntilObjectEnd(parser); consumeUntilObjectEnd(parser); - return InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(embeddingValueList); + return TextEmbeddingFloatResults.Embedding.of(embeddingValueList); } private static float parseEmbeddingList(XContentParser parser) throws IOException { diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntity.java index cdfe36447b88..423fbf4aaa5d 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntity.java @@ -14,7 +14,7 @@ import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; import org.elasticsearch.xpack.inference.external.response.XContentUtils; @@ -35,7 +35,7 @@ public class HuggingFaceEmbeddingsResponseEntity { * Parse the response from hugging face. The known formats are an array of arrays and object with an {@code embeddings} field containing * an array of arrays. */ - public static InferenceTextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { + public static TextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { var parserConfig = XContentParserConfiguration.EMPTY.withDeprecationHandler(LoggingDeprecationHandler.INSTANCE); try (XContentParser jsonParser = XContentFactory.xContent(XContentType.JSON).createParser(parserConfig, response.body())) { @@ -93,13 +93,13 @@ public class HuggingFaceEmbeddingsResponseEntity { * sentence-transformers/all-MiniLM-L6-v2 * sentence-transformers/all-MiniLM-L12-v2 */ - private static InferenceTextEmbeddingFloatResults parseArrayFormat(XContentParser parser) throws IOException { - List embeddingList = parseList( + private static TextEmbeddingFloatResults parseArrayFormat(XContentParser parser) throws IOException { + List embeddingList = parseList( parser, HuggingFaceEmbeddingsResponseEntity::parseEmbeddingEntry ); - return new InferenceTextEmbeddingFloatResults(embeddingList); + return new TextEmbeddingFloatResults(embeddingList); } /** @@ -138,23 +138,22 @@ public class HuggingFaceEmbeddingsResponseEntity { * intfloat/multilingual-e5-small * sentence-transformers/all-mpnet-base-v2 */ - private static InferenceTextEmbeddingFloatResults parseObjectFormat(XContentParser parser) throws IOException { + private static TextEmbeddingFloatResults parseObjectFormat(XContentParser parser) throws IOException { positionParserAtTokenAfterField(parser, "embeddings", FAILED_TO_FIND_FIELD_TEMPLATE); - List embeddingList = parseList( + List embeddingList = parseList( parser, HuggingFaceEmbeddingsResponseEntity::parseEmbeddingEntry ); - return new InferenceTextEmbeddingFloatResults(embeddingList); + return new TextEmbeddingFloatResults(embeddingList); } - private static InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding parseEmbeddingEntry(XContentParser parser) - throws IOException { + private static TextEmbeddingFloatResults.Embedding parseEmbeddingEntry(XContentParser parser) throws IOException { ensureExpectedToken(XContentParser.Token.START_ARRAY, parser.currentToken(), parser); List embeddingValuesList = parseList(parser, XContentUtils::parseFloat); - return InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(embeddingValuesList); + return TextEmbeddingFloatResults.Embedding.of(embeddingValuesList); } private HuggingFaceEmbeddingsResponseEntity() {} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/ibmwatsonx/IbmWatsonxEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/ibmwatsonx/IbmWatsonxEmbeddingsResponseEntity.java index 2702556bb983..81b1d9cd0f3f 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/ibmwatsonx/IbmWatsonxEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/ibmwatsonx/IbmWatsonxEmbeddingsResponseEntity.java @@ -12,7 +12,7 @@ import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; import org.elasticsearch.xpack.inference.external.response.XContentUtils; @@ -30,7 +30,7 @@ public class IbmWatsonxEmbeddingsResponseEntity { private static final String FAILED_TO_FIND_FIELD_TEMPLATE = "Failed to find required field [%s] in IBM Watsonx embeddings response"; - public static InferenceTextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { + public static TextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { var parserConfig = XContentParserConfiguration.EMPTY.withDeprecationHandler(LoggingDeprecationHandler.INSTANCE); try (XContentParser jsonParser = XContentFactory.xContent(XContentType.JSON).createParser(parserConfig, response.body())) { @@ -41,17 +41,16 @@ public class IbmWatsonxEmbeddingsResponseEntity { positionParserAtTokenAfterField(jsonParser, "results", FAILED_TO_FIND_FIELD_TEMPLATE); - List embeddingList = parseList( + List embeddingList = parseList( jsonParser, IbmWatsonxEmbeddingsResponseEntity::parseEmbeddingObject ); - return new InferenceTextEmbeddingFloatResults(embeddingList); + return new TextEmbeddingFloatResults(embeddingList); } } - private static InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding parseEmbeddingObject(XContentParser parser) - throws IOException { + private static TextEmbeddingFloatResults.Embedding parseEmbeddingObject(XContentParser parser) throws IOException { ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser); positionParserAtTokenAfterField(parser, "embedding", FAILED_TO_FIND_FIELD_TEMPLATE); @@ -60,7 +59,7 @@ public class IbmWatsonxEmbeddingsResponseEntity { // parse and discard the rest of the object consumeUntilObjectEnd(parser); - return InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(embeddingValuesList); + return TextEmbeddingFloatResults.Embedding.of(embeddingValuesList); } private IbmWatsonxEmbeddingsResponseEntity() {} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/jinaai/JinaAIEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/jinaai/JinaAIEmbeddingsResponseEntity.java index 26bde5f5f48a..b1782bb560ac 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/jinaai/JinaAIEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/jinaai/JinaAIEmbeddingsResponseEntity.java @@ -14,7 +14,7 @@ import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; import org.elasticsearch.xpack.inference.external.response.XContentUtils; @@ -73,7 +73,7 @@ public class JinaAIEmbeddingsResponseEntity { * * */ - public static InferenceTextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { + public static TextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { var parserConfig = XContentParserConfiguration.EMPTY.withDeprecationHandler(LoggingDeprecationHandler.INSTANCE); try (XContentParser jsonParser = XContentFactory.xContent(XContentType.JSON).createParser(parserConfig, response.body())) { @@ -84,17 +84,16 @@ public class JinaAIEmbeddingsResponseEntity { positionParserAtTokenAfterField(jsonParser, "data", FAILED_TO_FIND_FIELD_TEMPLATE); - List embeddingList = parseList( + List embeddingList = parseList( jsonParser, JinaAIEmbeddingsResponseEntity::parseEmbeddingObject ); - return new InferenceTextEmbeddingFloatResults(embeddingList); + return new TextEmbeddingFloatResults(embeddingList); } } - private static InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding parseEmbeddingObject(XContentParser parser) - throws IOException { + private static TextEmbeddingFloatResults.Embedding parseEmbeddingObject(XContentParser parser) throws IOException { ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser); positionParserAtTokenAfterField(parser, "embedding", FAILED_TO_FIND_FIELD_TEMPLATE); @@ -103,7 +102,7 @@ public class JinaAIEmbeddingsResponseEntity { // parse and discard the rest of the object consumeUntilObjectEnd(parser); - return InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(embeddingValuesList); + return TextEmbeddingFloatResults.Embedding.of(embeddingValuesList); } private JinaAIEmbeddingsResponseEntity() {} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntity.java index ad6df0624708..bda5741af203 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntity.java @@ -14,7 +14,7 @@ import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; import org.elasticsearch.xpack.inference.external.response.XContentUtils; @@ -74,7 +74,7 @@ public class OpenAiEmbeddingsResponseEntity { * * */ - public static InferenceTextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { + public static TextEmbeddingFloatResults fromResponse(Request request, HttpResult response) throws IOException { var parserConfig = XContentParserConfiguration.EMPTY.withDeprecationHandler(LoggingDeprecationHandler.INSTANCE); try (XContentParser jsonParser = XContentFactory.xContent(XContentType.JSON).createParser(parserConfig, response.body())) { @@ -85,17 +85,16 @@ public class OpenAiEmbeddingsResponseEntity { positionParserAtTokenAfterField(jsonParser, "data", FAILED_TO_FIND_FIELD_TEMPLATE); - List embeddingList = parseList( + List embeddingList = parseList( jsonParser, OpenAiEmbeddingsResponseEntity::parseEmbeddingObject ); - return new InferenceTextEmbeddingFloatResults(embeddingList); + return new TextEmbeddingFloatResults(embeddingList); } } - private static InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding parseEmbeddingObject(XContentParser parser) - throws IOException { + private static TextEmbeddingFloatResults.Embedding parseEmbeddingObject(XContentParser parser) throws IOException { ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.currentToken(), parser); positionParserAtTokenAfterField(parser, "embedding", FAILED_TO_FIND_FIELD_TEMPLATE); @@ -104,7 +103,7 @@ public class OpenAiEmbeddingsResponseEntity { // parse and discard the rest of the object consumeUntilObjectEnd(parser); - return InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(embeddingValuesList); + return TextEmbeddingFloatResults.Embedding.of(embeddingValuesList); } private OpenAiEmbeddingsResponseEntity() {} diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/voyageai/VoyageAIEmbeddingsResponseEntity.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/voyageai/VoyageAIEmbeddingsResponseEntity.java index f2c6cb5db4c3..ed30df1a8bb2 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/voyageai/VoyageAIEmbeddingsResponseEntity.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/response/voyageai/VoyageAIEmbeddingsResponseEntity.java @@ -17,10 +17,9 @@ import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.InferenceByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingBitResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingByteResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingBitResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; import org.elasticsearch.xpack.inference.external.request.voyageai.VoyageAIEmbeddingsRequest; @@ -78,9 +77,9 @@ public class VoyageAIEmbeddingsResponseEntity { } } - public InferenceByteEmbedding toInferenceByteEmbedding() { + public TextEmbeddingByteResults.Embedding toInferenceByteEmbedding() { embedding.forEach(EmbeddingInt8ResultEntry::checkByteBounds); - return InferenceByteEmbedding.of(embedding.stream().map(Integer::byteValue).toList()); + return TextEmbeddingByteResults.Embedding.of(embedding.stream().map(Integer::byteValue).toList()); } } @@ -111,8 +110,8 @@ public class VoyageAIEmbeddingsResponseEntity { PARSER.declareFloatArray(constructorArg(), new ParseField("embedding")); } - public InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding toInferenceFloatEmbedding() { - return InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(embedding); + public TextEmbeddingFloatResults.Embedding toInferenceFloatEmbedding() { + return TextEmbeddingFloatResults.Embedding.of(embedding); } } @@ -169,22 +168,22 @@ public class VoyageAIEmbeddingsResponseEntity { if (embeddingType == null || embeddingType == VoyageAIEmbeddingType.FLOAT) { var embeddingResult = EmbeddingFloatResult.PARSER.apply(jsonParser, null); - List embeddingList = embeddingResult.entries.stream() + List embeddingList = embeddingResult.entries.stream() .map(EmbeddingFloatResultEntry::toInferenceFloatEmbedding) .toList(); - return new InferenceTextEmbeddingFloatResults(embeddingList); + return new TextEmbeddingFloatResults(embeddingList); } else if (embeddingType == VoyageAIEmbeddingType.INT8) { var embeddingResult = EmbeddingInt8Result.PARSER.apply(jsonParser, null); - List embeddingList = embeddingResult.entries.stream() + List embeddingList = embeddingResult.entries.stream() .map(EmbeddingInt8ResultEntry::toInferenceByteEmbedding) .toList(); - return new InferenceTextEmbeddingByteResults(embeddingList); + return new TextEmbeddingByteResults(embeddingList); } else if (embeddingType == VoyageAIEmbeddingType.BIT || embeddingType == VoyageAIEmbeddingType.BINARY) { var embeddingResult = EmbeddingInt8Result.PARSER.apply(jsonParser, null); - List embeddingList = embeddingResult.entries.stream() + List embeddingList = embeddingResult.entries.stream() .map(EmbeddingInt8ResultEntry::toInferenceByteEmbedding) .toList(); - return new InferenceTextEmbeddingBitResults(embeddingList); + return new TextEmbeddingBitResults(embeddingList); } else { throw new IllegalArgumentException( "Illegal embedding_type value: " + embeddingType + ". Supported types are: " + VALID_EMBEDDING_TYPES_STRING diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ServiceUtils.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ServiceUtils.java index 13d641101a1c..7330d45b6f16 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ServiceUtils.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ServiceUtils.java @@ -22,8 +22,8 @@ import org.elasticsearch.inference.SimilarityMeasure; import org.elasticsearch.inference.TaskType; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; -import org.elasticsearch.xpack.core.inference.results.TextEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; import org.elasticsearch.xpack.core.ml.inference.assignment.AdaptiveAllocationsSettings; import org.elasticsearch.xpack.inference.services.settings.ApiKeySecrets; @@ -741,7 +741,7 @@ public final class ServiceUtils { InputType.INGEST, InferenceAction.Request.DEFAULT_TIMEOUT, listener.delegateFailureAndWrap((delegate, r) -> { - if (r instanceof TextEmbedding embeddingResults) { + if (r instanceof TextEmbeddingResults embeddingResults) { try { delegate.onResponse(embeddingResults.getFirstEmbeddingSize()); } catch (Exception e) { @@ -754,7 +754,7 @@ public final class ServiceUtils { new ElasticsearchStatusException( "Could not determine embedding size. " + "Expected a result of type [" - + InferenceTextEmbeddingFloatResults.NAME + + TextEmbeddingFloatResults.NAME + "] got [" + r.getWriteableName() + "]", diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/alibabacloudsearch/AlibabaCloudSearchService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/alibabacloudsearch/AlibabaCloudSearchService.java index 589ca1e033f0..dd2b29ec3efe 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/alibabacloudsearch/AlibabaCloudSearchService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/alibabacloudsearch/AlibabaCloudSearchService.java @@ -308,7 +308,6 @@ public class AlibabaCloudSearchService extends SenderService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), EMBEDDING_MAX_BATCH_SIZE, - getEmbeddingTypeFromTaskType(alibabaCloudSearchModel.getTaskType()), alibabaCloudSearchModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); @@ -318,14 +317,6 @@ public class AlibabaCloudSearchService extends SenderService { } } - private EmbeddingRequestChunker.EmbeddingType getEmbeddingTypeFromTaskType(TaskType taskType) { - return switch (taskType) { - case TEXT_EMBEDDING -> EmbeddingRequestChunker.EmbeddingType.FLOAT; - case SPARSE_EMBEDDING -> EmbeddingRequestChunker.EmbeddingType.SPARSE; - default -> throw new IllegalArgumentException("Unsupported task type for chunking: " + taskType); - }; - } - /** * For text embedding models get the embedding size and * update the service settings. diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/amazonbedrock/AmazonBedrockService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/amazonbedrock/AmazonBedrockService.java index 493acd3c0cd1..b9361a2e6623 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/amazonbedrock/AmazonBedrockService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/amazonbedrock/AmazonBedrockService.java @@ -132,7 +132,6 @@ public class AmazonBedrockService extends SenderService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), maxBatchSize, - EmbeddingRequestChunker.EmbeddingType.FLOAT, baseAmazonBedrockModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/azureaistudio/AzureAiStudioService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/azureaistudio/AzureAiStudioService.java index 34a5c2b4cc1e..c82d0753edee 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/azureaistudio/AzureAiStudioService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/azureaistudio/AzureAiStudioService.java @@ -124,7 +124,6 @@ public class AzureAiStudioService extends SenderService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), EMBEDDING_MAX_BATCH_SIZE, - EmbeddingRequestChunker.EmbeddingType.FLOAT, baseAzureAiStudioModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/azureopenai/AzureOpenAiService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/azureopenai/AzureOpenAiService.java index 9a77b6333797..0f3e84e7c13e 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/azureopenai/AzureOpenAiService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/azureopenai/AzureOpenAiService.java @@ -284,7 +284,6 @@ public class AzureOpenAiService extends SenderService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), EMBEDDING_MAX_BATCH_SIZE, - EmbeddingRequestChunker.EmbeddingType.FLOAT, azureOpenAiModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/CohereService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/CohereService.java index 6c2d3bb96d74..08ab5f1ba86d 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/CohereService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/cohere/CohereService.java @@ -286,7 +286,6 @@ public class CohereService extends SenderService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), EMBEDDING_MAX_BATCH_SIZE, - EmbeddingRequestChunker.EmbeddingType.fromDenseVectorElementType(model.getServiceSettings().elementType()), cohereModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceService.java index 849babe1a9ab..9ea816757fe1 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceService.java @@ -33,7 +33,7 @@ import org.elasticsearch.inference.configuration.SettingsConfigurationFieldType; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.tasks.Task; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceError; import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; import org.elasticsearch.xpack.core.ml.inference.results.ErrorInferenceResults; @@ -578,7 +578,7 @@ public class ElasticInferenceService extends SenderService { private static List translateToChunkedResults(InferenceInputs inputs, InferenceServiceResults inferenceResults) { if (inferenceResults instanceof SparseEmbeddingResults sparseEmbeddingResults) { var inputsAsList = DocumentsOnlyInput.of(inputs).getInputs(); - return ChunkedInferenceEmbeddingSparse.listOf(inputsAsList, sparseEmbeddingResults); + return ChunkedInferenceEmbedding.listOf(inputsAsList, sparseEmbeddingResults); } else if (inferenceResults instanceof ErrorInferenceResults error) { return List.of(new ChunkedInferenceError(error.getException())); } else { diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalService.java index ddc5e3e1aa36..1beb476832b2 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalService.java @@ -35,9 +35,9 @@ import org.elasticsearch.inference.UnifiedCompletionRequest; import org.elasticsearch.inference.configuration.SettingsConfigurationFieldType; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.xpack.core.XPackSettings; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; import org.elasticsearch.xpack.core.inference.results.RankedDocsResults; import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.core.ml.action.GetDeploymentStatsAction; import org.elasticsearch.xpack.core.ml.action.GetTrainedModelsAction; import org.elasticsearch.xpack.core.ml.action.InferModelAction; @@ -635,7 +635,7 @@ public class ElasticsearchInternalService extends BaseElasticsearchInternalServi ); ActionListener mlResultsListener = listener.delegateFailureAndWrap( - (l, inferenceResult) -> l.onResponse(InferenceTextEmbeddingFloatResults.of(inferenceResult.getInferenceResults())) + (l, inferenceResult) -> l.onResponse(TextEmbeddingFloatResults.of(inferenceResult.getInferenceResults())) ); var maybeDeployListener = mlResultsListener.delegateResponse( @@ -728,7 +728,6 @@ public class ElasticsearchInternalService extends BaseElasticsearchInternalServi List batchedRequests = new EmbeddingRequestChunker( input, EMBEDDING_MAX_BATCH_SIZE, - embeddingTypeFromTaskTypeAndSettings(model.getTaskType(), esModel.internalServiceSettings), esModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); @@ -751,13 +750,11 @@ public class ElasticsearchInternalService extends BaseElasticsearchInternalServi ActionListener chunkPartListener ) { if (taskType == TaskType.TEXT_EMBEDDING) { - var translated = new ArrayList(); + var translated = new ArrayList(); for (var inferenceResult : inferenceResults) { if (inferenceResult instanceof MlTextEmbeddingResults mlTextEmbeddingResult) { - translated.add( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(mlTextEmbeddingResult.getInferenceAsFloat()) - ); + translated.add(new TextEmbeddingFloatResults.Embedding(mlTextEmbeddingResult.getInferenceAsFloat())); } else if (inferenceResult instanceof ErrorInferenceResults error) { chunkPartListener.onFailure(error.getException()); return; @@ -768,7 +765,7 @@ public class ElasticsearchInternalService extends BaseElasticsearchInternalServi return; } } - chunkPartListener.onResponse(new InferenceTextEmbeddingFloatResults(translated)); + chunkPartListener.onResponse(new TextEmbeddingFloatResults(translated)); } else { // sparse var translated = new ArrayList(); @@ -946,23 +943,6 @@ public class ElasticsearchInternalService extends BaseElasticsearchInternalServi return DEFAULT_ELSER_ID.equals(inferenceId) || DEFAULT_E5_ID.equals(inferenceId) || DEFAULT_RERANK_ID.equals(inferenceId); } - static EmbeddingRequestChunker.EmbeddingType embeddingTypeFromTaskTypeAndSettings( - TaskType taskType, - ElasticsearchInternalServiceSettings serviceSettings - ) { - return switch (taskType) { - case SPARSE_EMBEDDING -> EmbeddingRequestChunker.EmbeddingType.SPARSE; - case TEXT_EMBEDDING -> serviceSettings.elementType() == null - ? EmbeddingRequestChunker.EmbeddingType.FLOAT - : EmbeddingRequestChunker.EmbeddingType.fromDenseVectorElementType(serviceSettings.elementType()); - default -> throw new ElasticsearchStatusException( - "Chunking is not supported for task type [{}]", - RestStatus.BAD_REQUEST, - taskType - ); - }; - } - private void validateAgainstDeployment( String modelId, String deploymentId, diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googleaistudio/GoogleAiStudioService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googleaistudio/GoogleAiStudioService.java index 205cc545a23f..29b5fca47eab 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googleaistudio/GoogleAiStudioService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googleaistudio/GoogleAiStudioService.java @@ -331,7 +331,6 @@ public class GoogleAiStudioService extends SenderService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), EMBEDDING_MAX_BATCH_SIZE, - EmbeddingRequestChunker.EmbeddingType.FLOAT, googleAiStudioModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googlevertexai/GoogleVertexAiService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googlevertexai/GoogleVertexAiService.java index 3e921f669e86..29f7cdee7570 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googlevertexai/GoogleVertexAiService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/googlevertexai/GoogleVertexAiService.java @@ -231,7 +231,6 @@ public class GoogleVertexAiService extends SenderService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), EMBEDDING_MAX_BATCH_SIZE, - EmbeddingRequestChunker.EmbeddingType.FLOAT, googleVertexAiModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceService.java index 73c1446b9bb2..ce1a31c90ed7 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceService.java @@ -130,7 +130,6 @@ public class HuggingFaceService extends HuggingFaceBaseService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), EMBEDDING_MAX_BATCH_SIZE, - EmbeddingRequestChunker.EmbeddingType.FLOAT, huggingFaceModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/elser/HuggingFaceElserService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/elser/HuggingFaceElserService.java index 79001f17a4e9..434b94e6f8ac 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/elser/HuggingFaceElserService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/huggingface/elser/HuggingFaceElserService.java @@ -25,11 +25,10 @@ import org.elasticsearch.inference.SettingsConfiguration; import org.elasticsearch.inference.TaskType; import org.elasticsearch.inference.configuration.SettingsConfigurationFieldType; import org.elasticsearch.rest.RestStatus; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceError; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.core.ml.inference.results.ErrorInferenceResults; import org.elasticsearch.xpack.inference.external.http.sender.DocumentsOnlyInput; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; @@ -111,16 +110,16 @@ public class HuggingFaceElserService extends HuggingFaceBaseService { } private static List translateToChunkedResults(DocumentsOnlyInput inputs, InferenceServiceResults inferenceResults) { - if (inferenceResults instanceof InferenceTextEmbeddingFloatResults textEmbeddingResults) { + if (inferenceResults instanceof TextEmbeddingFloatResults textEmbeddingResults) { validateInputSizeAgainstEmbeddings(inputs.getInputs(), textEmbeddingResults.embeddings().size()); var results = new ArrayList(inputs.getInputs().size()); for (int i = 0; i < inputs.getInputs().size(); i++) { results.add( - new ChunkedInferenceEmbeddingFloat( + new ChunkedInferenceEmbedding( List.of( - new ChunkedInferenceEmbeddingFloat.FloatEmbeddingChunk( + new TextEmbeddingFloatResults.Chunk( textEmbeddingResults.embeddings().get(i).values(), inputs.getInputs().get(i), new ChunkedInference.TextOffset(0, inputs.getInputs().get(i).length()) @@ -132,13 +131,13 @@ public class HuggingFaceElserService extends HuggingFaceBaseService { return results; } else if (inferenceResults instanceof SparseEmbeddingResults sparseEmbeddingResults) { var inputsAsList = DocumentsOnlyInput.of(inputs).getInputs(); - return ChunkedInferenceEmbeddingSparse.listOf(inputsAsList, sparseEmbeddingResults); + return ChunkedInferenceEmbedding.listOf(inputsAsList, sparseEmbeddingResults); } else if (inferenceResults instanceof ErrorInferenceResults error) { return List.of(new ChunkedInferenceError(error.getException())); } else { String expectedClasses = Strings.format( "One of [%s,%s]", - InferenceTextEmbeddingFloatResults.class.getSimpleName(), + TextEmbeddingFloatResults.class.getSimpleName(), SparseEmbeddingResults.class.getSimpleName() ); throw createInvalidChunkedResultException(expectedClasses, inferenceResults.getWriteableName()); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ibmwatsonx/IbmWatsonxService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ibmwatsonx/IbmWatsonxService.java index 3fa423c2dae1..599187048968 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ibmwatsonx/IbmWatsonxService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/ibmwatsonx/IbmWatsonxService.java @@ -310,7 +310,6 @@ public class IbmWatsonxService extends SenderService { var batchedRequests = new EmbeddingRequestChunker( input.getInputs(), EMBEDDING_MAX_BATCH_SIZE, - EmbeddingRequestChunker.EmbeddingType.FLOAT, model.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); for (var request : batchedRequests) { diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/jinaai/JinaAIService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/jinaai/JinaAIService.java index 37add1e26470..71917151623f 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/jinaai/JinaAIService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/jinaai/JinaAIService.java @@ -268,7 +268,6 @@ public class JinaAIService extends SenderService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), EMBEDDING_MAX_BATCH_SIZE, - EmbeddingRequestChunker.EmbeddingType.fromDenseVectorElementType(model.getServiceSettings().elementType()), jinaaiModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/mistral/MistralService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/mistral/MistralService.java index 3e40575e42fa..1f50173951db 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/mistral/MistralService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/mistral/MistralService.java @@ -113,7 +113,6 @@ public class MistralService extends SenderService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), MistralConstants.MAX_BATCH_SIZE, - EmbeddingRequestChunker.EmbeddingType.FLOAT, mistralEmbeddingsModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/openai/OpenAiService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/openai/OpenAiService.java index 94312a39882f..4651781c3a4d 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/openai/OpenAiService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/openai/OpenAiService.java @@ -322,7 +322,6 @@ public class OpenAiService extends SenderService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), EMBEDDING_MAX_BATCH_SIZE, - EmbeddingRequestChunker.EmbeddingType.FLOAT, openAiModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/validation/TextEmbeddingModelValidator.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/validation/TextEmbeddingModelValidator.java index 1fe5c684196f..766d7436d329 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/validation/TextEmbeddingModelValidator.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/validation/TextEmbeddingModelValidator.java @@ -14,8 +14,8 @@ import org.elasticsearch.inference.InferenceService; import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.inference.Model; import org.elasticsearch.rest.RestStatus; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; -import org.elasticsearch.xpack.core.inference.results.TextEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingResults; public class TextEmbeddingModelValidator implements ModelValidator { @@ -33,7 +33,7 @@ public class TextEmbeddingModelValidator implements ModelValidator { } private Model postValidate(InferenceService service, Model model, InferenceServiceResults results) { - if (results instanceof TextEmbedding embeddingResults) { + if (results instanceof TextEmbeddingResults embeddingResults) { var serviceSettings = model.getServiceSettings(); var dimensions = serviceSettings.dimensions(); int embeddingSize = getEmbeddingSize(embeddingResults); @@ -58,7 +58,7 @@ public class TextEmbeddingModelValidator implements ModelValidator { throw new ElasticsearchStatusException( "Validation call did not return expected results type." + "Expected a result of type [" - + InferenceTextEmbeddingFloatResults.NAME + + TextEmbeddingFloatResults.NAME + "] got [" + (results == null ? "null" : results.getWriteableName()) + "]", @@ -67,7 +67,7 @@ public class TextEmbeddingModelValidator implements ModelValidator { } } - private int getEmbeddingSize(TextEmbedding embeddingResults) { + private int getEmbeddingSize(TextEmbeddingResults embeddingResults) { int embeddingSize; try { embeddingSize = embeddingResults.getFirstEmbeddingSize(); diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIService.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIService.java index f92779de9b7f..16659f075c56 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIService.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIService.java @@ -291,7 +291,6 @@ public class VoyageAIService extends SenderService { List batchedRequests = new EmbeddingRequestChunker( inputs.getInputs(), getBatchSize(voyageaiModel), - EmbeddingRequestChunker.EmbeddingType.fromDenseVectorElementType(model.getServiceSettings().elementType()), voyageaiModel.getConfigurations().getChunkingSettings() ).batchRequestsWithListeners(listener); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterTests.java index 84c3e5cf80b0..dff740dfc926 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterTests.java @@ -50,7 +50,7 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xcontent.json.JsonXContent; import org.elasticsearch.xpack.core.XPackField; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceError; import org.elasticsearch.xpack.inference.InferencePlugin; import org.elasticsearch.xpack.inference.mapper.SemanticTextField; @@ -652,7 +652,7 @@ public class ShardBulkInferenceActionFilterTests extends ESTestCase { } ChunkedInference getResults(String text) { - return resultMap.getOrDefault(text, new ChunkedInferenceEmbeddingSparse(List.of())); + return resultMap.getOrDefault(text, new ChunkedInferenceEmbedding(List.of())); } void putResult(String text, ChunkedInference result) { diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/EmbeddingRequestChunkerTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/EmbeddingRequestChunkerTests.java index f0b82f49d4e9..23912b4000d0 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/EmbeddingRequestChunkerTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/chunking/EmbeddingRequestChunkerTests.java @@ -10,14 +10,11 @@ package org.elasticsearch.xpack.inference.chunking; import org.elasticsearch.action.ActionListener; import org.elasticsearch.inference.ChunkedInference; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingByte; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceError; -import org.elasticsearch.xpack.core.inference.results.InferenceByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingByteResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.core.ml.search.WeightedToken; import org.hamcrest.Matchers; @@ -27,6 +24,7 @@ import java.util.concurrent.atomic.AtomicReference; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.empty; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.startsWith; @@ -34,21 +32,19 @@ import static org.hamcrest.Matchers.startsWith; public class EmbeddingRequestChunkerTests extends ESTestCase { public void testEmptyInput_WordChunker() { - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - var batches = new EmbeddingRequestChunker(List.of(), 100, 100, 10, embeddingType).batchRequestsWithListeners(testListener()); + var batches = new EmbeddingRequestChunker(List.of(), 100, 100, 10).batchRequestsWithListeners(testListener()); assertThat(batches, empty()); } public void testEmptyInput_SentenceChunker() { - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - var batches = new EmbeddingRequestChunker(List.of(), 10, embeddingType, new SentenceBoundaryChunkingSettings(250, 1)) - .batchRequestsWithListeners(testListener()); + var batches = new EmbeddingRequestChunker(List.of(), 10, new SentenceBoundaryChunkingSettings(250, 1)).batchRequestsWithListeners( + testListener() + ); assertThat(batches, empty()); } public void testWhitespaceInput_SentenceChunker() { - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - var batches = new EmbeddingRequestChunker(List.of(" "), 10, embeddingType, new SentenceBoundaryChunkingSettings(250, 1)) + var batches = new EmbeddingRequestChunker(List.of(" "), 10, new SentenceBoundaryChunkingSettings(250, 1)) .batchRequestsWithListeners(testListener()); assertThat(batches, hasSize(1)); assertThat(batches.get(0).batch().inputs(), hasSize(1)); @@ -56,35 +52,30 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { } public void testBlankInput_WordChunker() { - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - var batches = new EmbeddingRequestChunker(List.of(""), 100, 100, 10, embeddingType).batchRequestsWithListeners(testListener()); + var batches = new EmbeddingRequestChunker(List.of(""), 100, 100, 10).batchRequestsWithListeners(testListener()); assertThat(batches, hasSize(1)); assertThat(batches.get(0).batch().inputs(), hasSize(1)); assertThat(batches.get(0).batch().inputs().get(0), Matchers.is("")); } public void testBlankInput_SentenceChunker() { - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - var batches = new EmbeddingRequestChunker(List.of(""), 10, embeddingType, new SentenceBoundaryChunkingSettings(250, 1)) - .batchRequestsWithListeners(testListener()); + var batches = new EmbeddingRequestChunker(List.of(""), 10, new SentenceBoundaryChunkingSettings(250, 1)).batchRequestsWithListeners( + testListener() + ); assertThat(batches, hasSize(1)); assertThat(batches.get(0).batch().inputs(), hasSize(1)); assertThat(batches.get(0).batch().inputs().get(0), Matchers.is("")); } public void testInputThatDoesNotChunk_WordChunker() { - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - var batches = new EmbeddingRequestChunker(List.of("ABBAABBA"), 100, 100, 10, embeddingType).batchRequestsWithListeners( - testListener() - ); + var batches = new EmbeddingRequestChunker(List.of("ABBAABBA"), 100, 100, 10).batchRequestsWithListeners(testListener()); assertThat(batches, hasSize(1)); assertThat(batches.get(0).batch().inputs(), hasSize(1)); assertThat(batches.get(0).batch().inputs().get(0), Matchers.is("ABBAABBA")); } public void testInputThatDoesNotChunk_SentenceChunker() { - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - var batches = new EmbeddingRequestChunker(List.of("ABBAABBA"), 10, embeddingType, new SentenceBoundaryChunkingSettings(250, 1)) + var batches = new EmbeddingRequestChunker(List.of("ABBAABBA"), 10, new SentenceBoundaryChunkingSettings(250, 1)) .batchRequestsWithListeners(testListener()); assertThat(batches, hasSize(1)); assertThat(batches.get(0).batch().inputs(), hasSize(1)); @@ -93,27 +84,22 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { public void testShortInputsAreSingleBatch() { String input = "one chunk"; - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - - var batches = new EmbeddingRequestChunker(List.of(input), 100, 100, 10, embeddingType).batchRequestsWithListeners(testListener()); + var batches = new EmbeddingRequestChunker(List.of(input), 100, 100, 10).batchRequestsWithListeners(testListener()); assertThat(batches, hasSize(1)); assertThat(batches.get(0).batch().inputs(), contains(input)); } public void testMultipleShortInputsAreSingleBatch() { List inputs = List.of("1st small", "2nd small", "3rd small"); - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - - var batches = new EmbeddingRequestChunker(inputs, 100, 100, 10, embeddingType).batchRequestsWithListeners(testListener()); + var batches = new EmbeddingRequestChunker(inputs, 100, 100, 10).batchRequestsWithListeners(testListener()); assertThat(batches, hasSize(1)); - assertEquals(batches.get(0).batch().inputs(), inputs); - var subBatches = batches.get(0).batch().subBatches(); + EmbeddingRequestChunker.BatchRequest batch = batches.getFirst().batch(); + assertEquals(batch.inputs(), inputs); for (int i = 0; i < inputs.size(); i++) { - var subBatch = subBatches.get(i); - assertThat(subBatch.requests().toChunkText(), contains(inputs.get(i))); - assertEquals(0, subBatch.positions().chunkIndex()); - assertEquals(i, subBatch.positions().inputIndex()); - assertEquals(1, subBatch.positions().embeddingCount()); + var request = batch.requests().get(i); + assertThat(request.chunkText(), equalTo(inputs.get(i))); + assertEquals(i, request.inputIndex()); + assertEquals(0, request.chunkIndex()); } } @@ -121,15 +107,12 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { int maxNumInputsPerBatch = 10; int numInputs = maxNumInputsPerBatch * 3 + 1; // requires 4 batches var inputs = new ArrayList(); - // + for (int i = 0; i < numInputs; i++) { inputs.add("input " + i); } - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - var batches = new EmbeddingRequestChunker(inputs, maxNumInputsPerBatch, 100, 10, embeddingType).batchRequestsWithListeners( - testListener() - ); + var batches = new EmbeddingRequestChunker(inputs, maxNumInputsPerBatch, 100, 10).batchRequestsWithListeners(testListener()); assertThat(batches, hasSize(4)); assertThat(batches.get(0).batch().inputs(), hasSize(maxNumInputsPerBatch)); assertThat(batches.get(1).batch().inputs(), hasSize(maxNumInputsPerBatch)); @@ -146,15 +129,12 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { assertEquals("input 29", batches.get(2).batch().inputs().get(9)); assertThat(batches.get(3).batch().inputs(), contains("input 30")); - int inputIndex = 0; - var subBatches = batches.get(0).batch().subBatches(); - for (int i = 0; i < batches.size(); i++) { - var subBatch = subBatches.get(i); - assertThat(subBatch.requests().toChunkText(), contains(inputs.get(i))); - assertEquals(0, subBatch.positions().chunkIndex()); - assertEquals(inputIndex, subBatch.positions().inputIndex()); - assertEquals(1, subBatch.positions().embeddingCount()); - inputIndex++; + List requests = batches.get(0).batch().requests(); + for (int i = 0; i < requests.size(); i++) { + EmbeddingRequestChunker.Request request = requests.get(i); + assertThat(request.chunkText(), equalTo(inputs.get(i))); + assertThat(request.inputIndex(), equalTo(i)); + assertThat(request.chunkIndex(), equalTo(0)); } } @@ -166,14 +146,9 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { for (int i = 0; i < numInputs; i++) { inputs.add("input " + i); } - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - var batches = new EmbeddingRequestChunker( - inputs, - maxNumInputsPerBatch, - embeddingType, - ChunkingSettingsTests.createRandomChunkingSettings() - ).batchRequestsWithListeners(testListener()); + var batches = new EmbeddingRequestChunker(inputs, maxNumInputsPerBatch, ChunkingSettingsTests.createRandomChunkingSettings()) + .batchRequestsWithListeners(testListener()); assertThat(batches, hasSize(4)); assertThat(batches.get(0).batch().inputs(), hasSize(maxNumInputsPerBatch)); assertThat(batches.get(1).batch().inputs(), hasSize(maxNumInputsPerBatch)); @@ -190,15 +165,12 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { assertEquals("input 29", batches.get(2).batch().inputs().get(9)); assertThat(batches.get(3).batch().inputs(), contains("input 30")); - int inputIndex = 0; - var subBatches = batches.get(0).batch().subBatches(); - for (int i = 0; i < batches.size(); i++) { - var subBatch = subBatches.get(i); - assertThat(subBatch.requests().toChunkText(), contains(inputs.get(i))); - assertEquals(0, subBatch.positions().chunkIndex()); - assertEquals(inputIndex, subBatch.positions().inputIndex()); - assertEquals(1, subBatch.positions().embeddingCount()); - inputIndex++; + List requests = batches.get(0).batch().requests(); + for (int i = 0; i < requests.size(); i++) { + EmbeddingRequestChunker.Request request = requests.get(i); + assertThat(request.chunkText(), equalTo(inputs.get(i))); + assertThat(request.inputIndex(), equalTo(i)); + assertThat(request.chunkIndex(), equalTo(0)); } } @@ -216,63 +188,49 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { } List inputs = List.of("1st small", passageBuilder.toString(), "2nd small", "3rd small"); - var embeddingType = randomFrom(EmbeddingRequestChunker.EmbeddingType.values()); - var batches = new EmbeddingRequestChunker(inputs, batchSize, chunkSize, overlap, embeddingType).batchRequestsWithListeners( - testListener() - ); + var batches = new EmbeddingRequestChunker(inputs, batchSize, chunkSize, overlap).batchRequestsWithListeners(testListener()); + assertThat(batches, hasSize(2)); - { - var batch = batches.get(0).batch(); - assertThat(batch.inputs(), hasSize(batchSize)); - assertEquals(batchSize, batch.size()); - assertThat(batch.subBatches(), hasSize(2)); - { - var subBatch = batch.subBatches().get(0); - assertEquals(0, subBatch.positions().inputIndex()); - assertEquals(0, subBatch.positions().chunkIndex()); - assertEquals(1, subBatch.positions().embeddingCount()); - assertThat(subBatch.requests().toChunkText(), contains("1st small")); - } - { - var subBatch = batch.subBatches().get(1); - assertEquals(1, subBatch.positions().inputIndex()); // 2nd input - assertEquals(0, subBatch.positions().chunkIndex()); // 1st part of the 2nd input - assertEquals(4, subBatch.positions().embeddingCount()); // 4 chunks - assertThat(subBatch.requests().toChunkText().get(0), startsWith("passage_input0 ")); - assertThat(subBatch.requests().toChunkText().get(1), startsWith(" passage_input20 ")); - assertThat(subBatch.requests().toChunkText().get(2), startsWith(" passage_input40 ")); - assertThat(subBatch.requests().toChunkText().get(3), startsWith(" passage_input60 ")); - } + + var batch = batches.get(0).batch(); + assertThat(batch.inputs(), hasSize(batchSize)); + assertThat(batch.requests(), hasSize(batchSize)); + + EmbeddingRequestChunker.Request request = batch.requests().get(0); + assertThat(request.inputIndex(), equalTo(0)); + assertThat(request.chunkIndex(), equalTo(0)); + assertThat(request.chunkText(), equalTo("1st small")); + + for (int requestIndex = 1; requestIndex < 5; requestIndex++) { + request = batch.requests().get(requestIndex); + assertThat(request.inputIndex(), equalTo(1)); + int chunkIndex = requestIndex - 1; + assertThat(request.chunkIndex(), equalTo(chunkIndex)); + assertThat(request.chunkText(), startsWith((chunkIndex == 0 ? "" : " ") + "passage_input" + 20 * chunkIndex)); } - { - var batch = batches.get(1).batch(); - assertThat(batch.inputs(), hasSize(4)); - assertEquals(4, batch.size()); - assertThat(batch.subBatches(), hasSize(3)); - { - var subBatch = batch.subBatches().get(0); - assertEquals(1, subBatch.positions().inputIndex()); // 2nd input - assertEquals(1, subBatch.positions().chunkIndex()); // 2nd part of the 2nd input - assertEquals(2, subBatch.positions().embeddingCount()); - assertThat(subBatch.requests().toChunkText().get(0), startsWith(" passage_input80 ")); - assertThat(subBatch.requests().toChunkText().get(1), startsWith(" passage_input100 ")); - } - { - var subBatch = batch.subBatches().get(1); - assertEquals(2, subBatch.positions().inputIndex()); // 3rd input - assertEquals(0, subBatch.positions().chunkIndex()); // 1st and only part - assertEquals(1, subBatch.positions().embeddingCount()); // 1 chunk - assertThat(subBatch.requests().toChunkText(), contains("2nd small")); - } - { - var subBatch = batch.subBatches().get(2); - assertEquals(3, subBatch.positions().inputIndex()); // 4th input - assertEquals(0, subBatch.positions().chunkIndex()); // 1st and only part - assertEquals(1, subBatch.positions().embeddingCount()); // 1 chunk - assertThat(subBatch.requests().toChunkText(), contains("3rd small")); - } + + batch = batches.get(1).batch(); + assertThat(batch.inputs(), hasSize(4)); + assertThat(batch.requests(), hasSize(4)); + + for (int requestIndex = 0; requestIndex < 2; requestIndex++) { + request = batch.requests().get(requestIndex); + assertThat(request.inputIndex(), equalTo(1)); + int chunkIndex = requestIndex + 4; + assertThat(request.chunkIndex(), equalTo(chunkIndex)); + assertThat(request.chunkText(), startsWith(" passage_input" + 20 * chunkIndex)); } + + request = batch.requests().get(2); + assertThat(request.inputIndex(), equalTo(2)); + assertThat(request.chunkIndex(), equalTo(0)); + assertThat(request.chunkText(), equalTo("2nd small")); + + request = batch.requests().get(3); + assertThat(request.inputIndex(), equalTo(3)); + assertThat(request.chunkIndex(), equalTo(0)); + assertThat(request.chunkText(), equalTo("3rd small")); } public void testMergingListener_Float() { @@ -290,40 +248,39 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { List inputs = List.of("1st small", passageBuilder.toString(), "2nd small", "3rd small"); var finalListener = testListener(); - var batches = new EmbeddingRequestChunker(inputs, batchSize, chunkSize, overlap, EmbeddingRequestChunker.EmbeddingType.FLOAT) - .batchRequestsWithListeners(finalListener); + var batches = new EmbeddingRequestChunker(inputs, batchSize, chunkSize, overlap).batchRequestsWithListeners(finalListener); assertThat(batches, hasSize(2)); // 4 inputs in 2 batches { - var embeddings = new ArrayList(); + var embeddings = new ArrayList(); for (int i = 0; i < batchSize; i++) { - embeddings.add(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { randomFloat() })); + embeddings.add(new TextEmbeddingFloatResults.Embedding(new float[] { randomFloat() })); } - batches.get(0).listener().onResponse(new InferenceTextEmbeddingFloatResults(embeddings)); + batches.get(0).listener().onResponse(new TextEmbeddingFloatResults(embeddings)); } { - var embeddings = new ArrayList(); + var embeddings = new ArrayList(); for (int i = 0; i < 4; i++) { // 4 requests in the 2nd batch - embeddings.add(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { randomFloat() })); + embeddings.add(new TextEmbeddingFloatResults.Embedding(new float[] { randomFloat() })); } - batches.get(1).listener().onResponse(new InferenceTextEmbeddingFloatResults(embeddings)); + batches.get(1).listener().onResponse(new TextEmbeddingFloatResults(embeddings)); } assertNotNull(finalListener.results); assertThat(finalListener.results, hasSize(4)); { var chunkedResult = finalListener.results.get(0); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var chunkedFloatResult = (ChunkedInferenceEmbeddingFloat) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedFloatResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedFloatResult.chunks(), hasSize(1)); assertEquals("1st small", chunkedFloatResult.chunks().get(0).matchedText()); } { // this is the large input split in multiple chunks var chunkedResult = finalListener.results.get(1); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var chunkedFloatResult = (ChunkedInferenceEmbeddingFloat) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedFloatResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedFloatResult.chunks(), hasSize(6)); assertThat(chunkedFloatResult.chunks().get(0).matchedText(), startsWith("passage_input0 ")); assertThat(chunkedFloatResult.chunks().get(1).matchedText(), startsWith(" passage_input20 ")); @@ -334,15 +291,15 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { } { var chunkedResult = finalListener.results.get(2); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var chunkedFloatResult = (ChunkedInferenceEmbeddingFloat) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedFloatResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedFloatResult.chunks(), hasSize(1)); assertEquals("2nd small", chunkedFloatResult.chunks().get(0).matchedText()); } { var chunkedResult = finalListener.results.get(3); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var chunkedFloatResult = (ChunkedInferenceEmbeddingFloat) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedFloatResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedFloatResult.chunks(), hasSize(1)); assertEquals("3rd small", chunkedFloatResult.chunks().get(0).matchedText()); } @@ -363,40 +320,39 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { List inputs = List.of("1st small", passageBuilder.toString(), "2nd small", "3rd small"); var finalListener = testListener(); - var batches = new EmbeddingRequestChunker(inputs, batchSize, chunkSize, overlap, EmbeddingRequestChunker.EmbeddingType.BYTE) - .batchRequestsWithListeners(finalListener); + var batches = new EmbeddingRequestChunker(inputs, batchSize, chunkSize, overlap).batchRequestsWithListeners(finalListener); assertThat(batches, hasSize(2)); // 4 inputs in 2 batches { - var embeddings = new ArrayList(); + var embeddings = new ArrayList(); for (int i = 0; i < batchSize; i++) { - embeddings.add(new InferenceByteEmbedding(new byte[] { randomByte() })); + embeddings.add(new TextEmbeddingByteResults.Embedding(new byte[] { randomByte() })); } - batches.get(0).listener().onResponse(new InferenceTextEmbeddingByteResults(embeddings)); + batches.get(0).listener().onResponse(new TextEmbeddingByteResults(embeddings)); } { - var embeddings = new ArrayList(); + var embeddings = new ArrayList(); for (int i = 0; i < 4; i++) { // 4 requests in the 2nd batch - embeddings.add(new InferenceByteEmbedding(new byte[] { randomByte() })); + embeddings.add(new TextEmbeddingByteResults.Embedding(new byte[] { randomByte() })); } - batches.get(1).listener().onResponse(new InferenceTextEmbeddingByteResults(embeddings)); + batches.get(1).listener().onResponse(new TextEmbeddingByteResults(embeddings)); } assertNotNull(finalListener.results); assertThat(finalListener.results, hasSize(4)); { var chunkedResult = finalListener.results.get(0); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingByte.class)); - var chunkedByteResult = (ChunkedInferenceEmbeddingByte) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedByteResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedByteResult.chunks(), hasSize(1)); assertEquals("1st small", chunkedByteResult.chunks().get(0).matchedText()); } { // this is the large input split in multiple chunks var chunkedResult = finalListener.results.get(1); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingByte.class)); - var chunkedByteResult = (ChunkedInferenceEmbeddingByte) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedByteResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedByteResult.chunks(), hasSize(6)); assertThat(chunkedByteResult.chunks().get(0).matchedText(), startsWith("passage_input0 ")); assertThat(chunkedByteResult.chunks().get(1).matchedText(), startsWith(" passage_input20 ")); @@ -407,15 +363,15 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { } { var chunkedResult = finalListener.results.get(2); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingByte.class)); - var chunkedByteResult = (ChunkedInferenceEmbeddingByte) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedByteResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedByteResult.chunks(), hasSize(1)); assertEquals("2nd small", chunkedByteResult.chunks().get(0).matchedText()); } { var chunkedResult = finalListener.results.get(3); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingByte.class)); - var chunkedByteResult = (ChunkedInferenceEmbeddingByte) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedByteResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedByteResult.chunks(), hasSize(1)); assertEquals("3rd small", chunkedByteResult.chunks().get(0).matchedText()); } @@ -436,8 +392,7 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { List inputs = List.of("1st small", "2nd small", "3rd small", passageBuilder.toString()); var finalListener = testListener(); - var batches = new EmbeddingRequestChunker(inputs, batchSize, chunkSize, overlap, EmbeddingRequestChunker.EmbeddingType.SPARSE) - .batchRequestsWithListeners(finalListener); + var batches = new EmbeddingRequestChunker(inputs, batchSize, chunkSize, overlap).batchRequestsWithListeners(finalListener); assertThat(batches, hasSize(3)); // 4 inputs in 3 batches @@ -467,30 +422,30 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { assertThat(finalListener.results, hasSize(4)); { var chunkedResult = finalListener.results.get(0); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingSparse.class)); - var chunkedSparseResult = (ChunkedInferenceEmbeddingSparse) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedSparseResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedSparseResult.chunks(), hasSize(1)); assertEquals("1st small", chunkedSparseResult.chunks().get(0).matchedText()); } { var chunkedResult = finalListener.results.get(1); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingSparse.class)); - var chunkedSparseResult = (ChunkedInferenceEmbeddingSparse) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedSparseResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedSparseResult.chunks(), hasSize(1)); assertEquals("2nd small", chunkedSparseResult.chunks().get(0).matchedText()); } { var chunkedResult = finalListener.results.get(2); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingSparse.class)); - var chunkedSparseResult = (ChunkedInferenceEmbeddingSparse) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedSparseResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedSparseResult.chunks(), hasSize(1)); assertEquals("3rd small", chunkedSparseResult.chunks().get(0).matchedText()); } { // this is the large input split in multiple chunks var chunkedResult = finalListener.results.get(3); - assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbeddingSparse.class)); - var chunkedSparseResult = (ChunkedInferenceEmbeddingSparse) chunkedResult; + assertThat(chunkedResult, instanceOf(ChunkedInferenceEmbedding.class)); + var chunkedSparseResult = (ChunkedInferenceEmbedding) chunkedResult; assertThat(chunkedSparseResult.chunks(), hasSize(9)); // passage is split into 9 chunks, 10 words each assertThat(chunkedSparseResult.chunks().get(0).matchedText(), startsWith("passage_input0 ")); assertThat(chunkedSparseResult.chunks().get(1).matchedText(), startsWith(" passage_input10 ")); @@ -517,14 +472,13 @@ public class EmbeddingRequestChunkerTests extends ESTestCase { } }; - var batches = new EmbeddingRequestChunker(inputs, 10, 100, 0, EmbeddingRequestChunker.EmbeddingType.FLOAT) - .batchRequestsWithListeners(listener); + var batches = new EmbeddingRequestChunker(inputs, 10, 100, 0).batchRequestsWithListeners(listener); assertThat(batches, hasSize(1)); - var embeddings = new ArrayList(); - embeddings.add(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { randomFloat() })); - embeddings.add(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { randomFloat() })); - batches.get(0).listener().onResponse(new InferenceTextEmbeddingFloatResults(embeddings)); + var embeddings = new ArrayList(); + embeddings.add(new TextEmbeddingFloatResults.Embedding(new float[] { randomFloat() })); + embeddings.add(new TextEmbeddingFloatResults.Embedding(new float[] { randomFloat() })); + batches.get(0).listener().onResponse(new TextEmbeddingFloatResults(embeddings)); assertEquals("Error the number of embedding responses [2] does not equal the number of requests [3]", failureMessage.get()); } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/action/amazonbedrock/AmazonBedrockActionCreatorTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/action/amazonbedrock/AmazonBedrockActionCreatorTests.java index e7543aa6ba9e..e37e301dc422 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/action/amazonbedrock/AmazonBedrockActionCreatorTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/action/amazonbedrock/AmazonBedrockActionCreatorTests.java @@ -15,7 +15,7 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xpack.core.inference.action.InferenceAction; import org.elasticsearch.xpack.core.inference.results.ChatCompletionResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.amazonbedrock.AmazonBedrockMockRequestSender; import org.elasticsearch.xpack.inference.external.http.sender.ChatCompletionInput; import org.elasticsearch.xpack.inference.external.http.sender.DocumentsOnlyInput; @@ -52,8 +52,8 @@ public class AmazonBedrockActionCreatorTests extends ESTestCase { public void testEmbeddingsRequestAction() throws IOException { var serviceComponents = ServiceComponentsTests.createWithEmptySettings(threadPool); - var mockedFloatResults = List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.0123F, -0.0123F })); - var mockedResult = new InferenceTextEmbeddingFloatResults(mockedFloatResults); + var mockedFloatResults = List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.0123F, -0.0123F })); + var mockedResult = new TextEmbeddingFloatResults(mockedFloatResults); try (var sender = new AmazonBedrockMockRequestSender()) { sender.enqueue(mockedResult); var creator = new AmazonBedrockActionCreator(sender, serviceComponents, TIMEOUT); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/alibabacloudsearch/AlibabaCloudSearchEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/alibabacloudsearch/AlibabaCloudSearchEmbeddingsResponseEntityTests.java index 33fa6a2a542c..d9db5670611a 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/alibabacloudsearch/AlibabaCloudSearchEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/alibabacloudsearch/AlibabaCloudSearchEmbeddingsResponseEntityTests.java @@ -9,7 +9,7 @@ package org.elasticsearch.xpack.inference.external.response.alibabacloudsearch; import org.apache.http.HttpResponse; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.alibabacloudsearch.AlibabaCloudSearchRequest; @@ -50,20 +50,14 @@ public class AlibabaCloudSearchEmbeddingsResponseEntityTests extends ESTestCase URI uri = new URI("mock_uri"); when(request.getURI()).thenReturn(uri); - InferenceTextEmbeddingFloatResults parsedResults = AlibabaCloudSearchEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = AlibabaCloudSearchEmbeddingsResponseEntity.fromResponse( request, new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); assertThat( parsedResults.embeddings(), - is( - List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding( - new float[] { -0.02868066355586052f, 0.022033605724573135f } - ) - ) - ) + is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { -0.02868066355586052f, 0.022033605724573135f }))) ); } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/azureaistudio/AzureAiStudioEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/azureaistudio/AzureAiStudioEmbeddingsResponseEntityTests.java index c2f93554c6b2..1853ed41e4dc 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/azureaistudio/AzureAiStudioEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/azureaistudio/AzureAiStudioEmbeddingsResponseEntityTests.java @@ -9,7 +9,7 @@ package org.elasticsearch.xpack.inference.external.response.azureaistudio; import org.apache.http.HttpResponse; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -50,14 +50,11 @@ public class AzureAiStudioEmbeddingsResponseEntityTests extends ESTestCase { var entity = new AzureAiStudioEmbeddingsResponseEntity(); - var parsedResults = (InferenceTextEmbeddingFloatResults) entity.apply( + var parsedResults = (TextEmbeddingFloatResults) entity.apply( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(List.of(0.014539449F, -0.015288644F)))) - ); + assertThat(parsedResults.embeddings(), is(List.of(TextEmbeddingFloatResults.Embedding.of(List.of(0.014539449F, -0.015288644F))))); } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntityTests.java index 42dab0a9021b..d0093012d8ac 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/cohere/CohereEmbeddingsResponseEntityTests.java @@ -10,10 +10,9 @@ package org.elasticsearch.xpack.inference.external.response.cohere; import org.apache.http.HttpResponse; import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingBitResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingByteResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingBitResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; import org.hamcrest.MatcherAssert; @@ -57,10 +56,10 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - MatcherAssert.assertThat(parsedResults, instanceOf(InferenceTextEmbeddingFloatResults.class)); + MatcherAssert.assertThat(parsedResults, instanceOf(TextEmbeddingFloatResults.class)); MatcherAssert.assertThat( - ((InferenceTextEmbeddingFloatResults) parsedResults).embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { -0.0018434525F, 0.01777649F }))) + ((TextEmbeddingFloatResults) parsedResults).embeddings(), + is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { -0.0018434525F, 0.01777649F }))) ); } @@ -91,14 +90,14 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = (InferenceTextEmbeddingFloatResults) CohereEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = (TextEmbeddingFloatResults) CohereEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); MatcherAssert.assertThat( parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { -0.0018434525F, 0.01777649F }))) + is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { -0.0018434525F, 0.01777649F }))) ); } @@ -135,14 +134,14 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = (InferenceTextEmbeddingFloatResults) CohereEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = (TextEmbeddingFloatResults) CohereEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); MatcherAssert.assertThat( parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { -0.0018434525F, 0.01777649F }))) + is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { -0.0018434525F, 0.01777649F }))) ); } @@ -179,12 +178,15 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingByteResults parsedResults = (InferenceTextEmbeddingByteResults) CohereEmbeddingsResponseEntity.fromResponse( + TextEmbeddingByteResults parsedResults = (TextEmbeddingByteResults) CohereEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - MatcherAssert.assertThat(parsedResults.embeddings(), is(List.of(new InferenceByteEmbedding(new byte[] { (byte) -1, (byte) 0 })))); + MatcherAssert.assertThat( + parsedResults.embeddings(), + is(List.of(new TextEmbeddingByteResults.Embedding(new byte[] { (byte) -1, (byte) 0 }))) + ); } public void testFromResponse_ParsesBytes() throws IOException { @@ -214,12 +216,15 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingByteResults parsedResults = (InferenceTextEmbeddingByteResults) CohereEmbeddingsResponseEntity.fromResponse( + TextEmbeddingByteResults parsedResults = (TextEmbeddingByteResults) CohereEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - MatcherAssert.assertThat(parsedResults.embeddings(), is(List.of(new InferenceByteEmbedding(new byte[] { (byte) -1, (byte) 0 })))); + MatcherAssert.assertThat( + parsedResults.embeddings(), + is(List.of(new TextEmbeddingByteResults.Embedding(new byte[] { (byte) -1, (byte) 0 }))) + ); } public void testFromResponse_ParsesBytes_FromBinaryEmbeddingsEntry() throws IOException { @@ -252,14 +257,14 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingBitResults parsedResults = (InferenceTextEmbeddingBitResults) CohereEmbeddingsResponseEntity.fromResponse( + TextEmbeddingBitResults parsedResults = (TextEmbeddingBitResults) CohereEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); MatcherAssert.assertThat( parsedResults.embeddings(), - is(List.of(new InferenceByteEmbedding(new byte[] { (byte) -55, (byte) 74, (byte) 101, (byte) 67, (byte) 83 }))) + is(List.of(new TextEmbeddingByteResults.Embedding(new byte[] { (byte) -55, (byte) 74, (byte) 101, (byte) 67, (byte) 83 }))) ); } @@ -292,7 +297,7 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = (InferenceTextEmbeddingFloatResults) CohereEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = (TextEmbeddingFloatResults) CohereEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); @@ -301,8 +306,8 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { -0.0018434525F, 0.01777649F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { -0.123F, 0.123F }) + new TextEmbeddingFloatResults.Embedding(new float[] { -0.0018434525F, 0.01777649F }), + new TextEmbeddingFloatResults.Embedding(new float[] { -0.123F, 0.123F }) ) ) ); @@ -339,7 +344,7 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = (InferenceTextEmbeddingFloatResults) CohereEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = (TextEmbeddingFloatResults) CohereEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); @@ -348,8 +353,8 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { -0.0018434525F, 0.01777649F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { -0.123F, 0.123F }) + new TextEmbeddingFloatResults.Embedding(new float[] { -0.0018434525F, 0.01777649F }), + new TextEmbeddingFloatResults.Embedding(new float[] { -0.123F, 0.123F }) ) ) ); @@ -392,7 +397,7 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingBitResults parsedResults = (InferenceTextEmbeddingBitResults) CohereEmbeddingsResponseEntity.fromResponse( + TextEmbeddingBitResults parsedResults = (TextEmbeddingBitResults) CohereEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); @@ -401,8 +406,8 @@ public class CohereEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - new InferenceByteEmbedding(new byte[] { (byte) -55, (byte) 74, (byte) 101, (byte) 67 }), - new InferenceByteEmbedding(new byte[] { (byte) 34, (byte) -64, (byte) 97, (byte) 65, (byte) -42 }) + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) -55, (byte) 74, (byte) 101, (byte) 67 }), + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 34, (byte) -64, (byte) 97, (byte) 65, (byte) -42 }) ) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/googleaistudio/GoogleAiStudioEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/googleaistudio/GoogleAiStudioEmbeddingsResponseEntityTests.java index 170395e8af91..b58828dc24aa 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/googleaistudio/GoogleAiStudioEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/googleaistudio/GoogleAiStudioEmbeddingsResponseEntityTests.java @@ -9,7 +9,7 @@ package org.elasticsearch.xpack.inference.external.response.googleaistudio; import org.apache.http.HttpResponse; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -36,15 +36,12 @@ public class GoogleAiStudioEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = GoogleAiStudioEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = GoogleAiStudioEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(List.of(-0.00606332F, 0.058092743F)))) - ); + assertThat(parsedResults.embeddings(), is(List.of(TextEmbeddingFloatResults.Embedding.of(List.of(-0.00606332F, 0.058092743F))))); } public void testFromResponse_CreatesResultsForMultipleItems() throws IOException { @@ -67,7 +64,7 @@ public class GoogleAiStudioEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = GoogleAiStudioEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = GoogleAiStudioEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); @@ -76,8 +73,8 @@ public class GoogleAiStudioEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(List.of(-0.00606332F, 0.058092743F)), - InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(List.of(0.030681048F, 0.01714732F)) + TextEmbeddingFloatResults.Embedding.of(List.of(-0.00606332F, 0.058092743F)), + TextEmbeddingFloatResults.Embedding.of(List.of(0.030681048F, 0.01714732F)) ) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/googlevertexai/GoogleVertexAiEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/googlevertexai/GoogleVertexAiEmbeddingsResponseEntityTests.java index 39bf08a21a76..e0acd65c419f 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/googlevertexai/GoogleVertexAiEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/googlevertexai/GoogleVertexAiEmbeddingsResponseEntityTests.java @@ -9,7 +9,7 @@ package org.elasticsearch.xpack.inference.external.response.googlevertexai; import org.apache.http.HttpResponse; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -42,15 +42,12 @@ public class GoogleVertexAiEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = GoogleVertexAiEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = GoogleVertexAiEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(List.of(-0.123F, 0.123F)))) - ); + assertThat(parsedResults.embeddings(), is(List.of(TextEmbeddingFloatResults.Embedding.of(List.of(-0.123F, 0.123F))))); } public void testFromResponse_CreatesResultsForMultipleItems() throws IOException { @@ -85,7 +82,7 @@ public class GoogleVertexAiEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = GoogleVertexAiEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = GoogleVertexAiEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); @@ -94,8 +91,8 @@ public class GoogleVertexAiEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(List.of(-0.123F, 0.123F)), - InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(List.of(-0.456F, 0.456F)) + TextEmbeddingFloatResults.Embedding.of(List.of(-0.123F, 0.123F)), + TextEmbeddingFloatResults.Embedding.of(List.of(-0.456F, 0.456F)) ) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntityTests.java index 6f06a32f19a6..4ba6def4516b 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/huggingface/HuggingFaceEmbeddingsResponseEntityTests.java @@ -10,7 +10,7 @@ package org.elasticsearch.xpack.inference.external.response.huggingface; import org.apache.http.HttpResponse; import org.elasticsearch.common.ParsingException; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -32,14 +32,14 @@ public class HuggingFaceEmbeddingsResponseEntityTests extends ESTestCase { ] """; - InferenceTextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); assertThat( parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.014539449F, -0.015288644F }))) + is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.014539449F, -0.015288644F }))) ); } @@ -55,14 +55,14 @@ public class HuggingFaceEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); assertThat( parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.014539449F, -0.015288644F }))) + is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.014539449F, -0.015288644F }))) ); } @@ -80,7 +80,7 @@ public class HuggingFaceEmbeddingsResponseEntityTests extends ESTestCase { ] """; - InferenceTextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); @@ -89,8 +89,8 @@ public class HuggingFaceEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.014539449F, -0.015288644F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.0123F, -0.0123F }) + new TextEmbeddingFloatResults.Embedding(new float[] { 0.014539449F, -0.015288644F }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.0123F, -0.0123F }) ) ) ); @@ -112,7 +112,7 @@ public class HuggingFaceEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); @@ -121,8 +121,8 @@ public class HuggingFaceEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.014539449F, -0.015288644F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.0123F, -0.0123F }) + new TextEmbeddingFloatResults.Embedding(new float[] { 0.014539449F, -0.015288644F }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.0123F, -0.0123F }) ) ) ); @@ -255,15 +255,12 @@ public class HuggingFaceEmbeddingsResponseEntityTests extends ESTestCase { ] """; - InferenceTextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 1.0F }))) - ); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 1.0F })))); } public void testFromResponse_SucceedsWhenEmbeddingValueIsInt_ObjectFormat() throws IOException { @@ -277,15 +274,12 @@ public class HuggingFaceEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 1.0F }))) - ); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 1.0F })))); } public void testFromResponse_SucceedsWhenEmbeddingValueIsLong_ArrayFormat() throws IOException { @@ -297,15 +291,12 @@ public class HuggingFaceEmbeddingsResponseEntityTests extends ESTestCase { ] """; - InferenceTextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 4.0294965E10F }))) - ); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 4.0294965E10F })))); } public void testFromResponse_SucceedsWhenEmbeddingValueIsLong_ObjectFormat() throws IOException { @@ -319,15 +310,12 @@ public class HuggingFaceEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = HuggingFaceEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 4.0294965E10F }))) - ); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 4.0294965E10F })))); } public void testFromResponse_FailsWhenEmbeddingValueIsAnObject_ObjectFormat() { diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/ibmwatsonx/IbmWatsonxEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/ibmwatsonx/IbmWatsonxEmbeddingsResponseEntityTests.java index ae39f19b8317..b122eafe06a5 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/ibmwatsonx/IbmWatsonxEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/ibmwatsonx/IbmWatsonxEmbeddingsResponseEntityTests.java @@ -9,7 +9,7 @@ package org.elasticsearch.xpack.inference.external.response.ibmwatsonx; import org.apache.http.HttpResponse; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -36,15 +36,12 @@ public class IbmWatsonxEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = IbmWatsonxEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = IbmWatsonxEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(List.of(-0.00606332F, 0.058092743F)))) - ); + assertThat(parsedResults.embeddings(), is(List.of(TextEmbeddingFloatResults.Embedding.of(List.of(-0.00606332F, 0.058092743F))))); } public void testFromResponse_CreatesResultsForMultipleItems() throws IOException { @@ -69,7 +66,7 @@ public class IbmWatsonxEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = IbmWatsonxEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = IbmWatsonxEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); @@ -78,8 +75,8 @@ public class IbmWatsonxEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(List.of(-0.00606332F, 0.058092743F)), - InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding.of(List.of(0.030681048F, 0.01714732F)) + TextEmbeddingFloatResults.Embedding.of(List.of(-0.00606332F, 0.058092743F)), + TextEmbeddingFloatResults.Embedding.of(List.of(0.030681048F, 0.01714732F)) ) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/jinaai/JinaAIEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/jinaai/JinaAIEmbeddingsResponseEntityTests.java index 7dbb9d5441a4..a5f7c4eadae2 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/jinaai/JinaAIEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/jinaai/JinaAIEmbeddingsResponseEntityTests.java @@ -10,7 +10,7 @@ package org.elasticsearch.xpack.inference.external.response.jinaai; import org.apache.http.HttpResponse; import org.elasticsearch.common.ParsingException; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -44,14 +44,14 @@ public class JinaAIEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = JinaAIEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = JinaAIEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); assertThat( parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.014539449F, -0.015288644F }))) + is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.014539449F, -0.015288644F }))) ); } @@ -85,7 +85,7 @@ public class JinaAIEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = JinaAIEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = JinaAIEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); @@ -94,8 +94,8 @@ public class JinaAIEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.014539449F, -0.015288644F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.0123F, -0.0123F }) + new TextEmbeddingFloatResults.Embedding(new float[] { 0.014539449F, -0.015288644F }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.0123F, -0.0123F }) ) ) ); @@ -259,15 +259,12 @@ public class JinaAIEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = JinaAIEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = JinaAIEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 1.0F }))) - ); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 1.0F })))); } public void testFromResponse_SucceedsWhenEmbeddingValueIsLong() throws IOException { @@ -291,15 +288,12 @@ public class JinaAIEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = JinaAIEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = JinaAIEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 4.0294965E10F }))) - ); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 4.0294965E10F })))); } public void testFromResponse_FailsWhenEmbeddingValueIsAnObject() { @@ -378,7 +372,7 @@ public class JinaAIEmbeddingsResponseEntityTests extends ESTestCase { } }"""; - InferenceTextEmbeddingFloatResults parsedResults = JinaAIEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = JinaAIEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), response.getBytes(StandardCharsets.UTF_8)) ); @@ -387,9 +381,9 @@ public class JinaAIEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { -0.9F, 0.5F, 0.3F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.1F, 0.5F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.5F, 0.5F }) + new TextEmbeddingFloatResults.Embedding(new float[] { -0.9F, 0.5F, 0.3F }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.1F, 0.5F }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.5F, 0.5F }) ) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntityTests.java index 8f5bd95126fb..b5300f852e72 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/openai/OpenAiEmbeddingsResponseEntityTests.java @@ -10,7 +10,7 @@ package org.elasticsearch.xpack.inference.external.response.openai; import org.apache.http.HttpResponse; import org.elasticsearch.common.ParsingException; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.Request; @@ -44,14 +44,14 @@ public class OpenAiEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = OpenAiEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = OpenAiEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); assertThat( parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.014539449F, -0.015288644F }))) + is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.014539449F, -0.015288644F }))) ); } @@ -85,7 +85,7 @@ public class OpenAiEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = OpenAiEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = OpenAiEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); @@ -94,8 +94,8 @@ public class OpenAiEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.014539449F, -0.015288644F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.0123F, -0.0123F }) + new TextEmbeddingFloatResults.Embedding(new float[] { 0.014539449F, -0.015288644F }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.0123F, -0.0123F }) ) ) ); @@ -259,15 +259,12 @@ public class OpenAiEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = OpenAiEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = OpenAiEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 1.0F }))) - ); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 1.0F })))); } public void testFromResponse_SucceedsWhenEmbeddingValueIsLong() throws IOException { @@ -291,15 +288,12 @@ public class OpenAiEmbeddingsResponseEntityTests extends ESTestCase { } """; - InferenceTextEmbeddingFloatResults parsedResults = OpenAiEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = OpenAiEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), responseJson.getBytes(StandardCharsets.UTF_8)) ); - assertThat( - parsedResults.embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 4.0294965E10F }))) - ); + assertThat(parsedResults.embeddings(), is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 4.0294965E10F })))); } public void testFromResponse_FailsWhenEmbeddingValueIsAnObject() { @@ -379,7 +373,7 @@ public class OpenAiEmbeddingsResponseEntityTests extends ESTestCase { } }"""; - InferenceTextEmbeddingFloatResults parsedResults = OpenAiEmbeddingsResponseEntity.fromResponse( + TextEmbeddingFloatResults parsedResults = OpenAiEmbeddingsResponseEntity.fromResponse( mock(Request.class), new HttpResult(mock(HttpResponse.class), response.getBytes(StandardCharsets.UTF_8)) ); @@ -388,9 +382,9 @@ public class OpenAiEmbeddingsResponseEntityTests extends ESTestCase { parsedResults.embeddings(), is( List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { -0.9F, 0.5F, 0.3F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.1F, 0.5F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.5F, 0.5F }) + new TextEmbeddingFloatResults.Embedding(new float[] { -0.9F, 0.5F, 0.3F }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.1F, 0.5F }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.5F, 0.5F }) ) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/voyageai/VoyageAIEmbeddingsResponseEntityTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/voyageai/VoyageAIEmbeddingsResponseEntityTests.java index 2b1c8fa43af5..f91afc665f6d 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/voyageai/VoyageAIEmbeddingsResponseEntityTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/response/voyageai/VoyageAIEmbeddingsResponseEntityTests.java @@ -11,7 +11,7 @@ import org.apache.http.HttpResponse; import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xcontent.XContentParseException; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpResult; import org.elasticsearch.xpack.inference.external.request.voyageai.VoyageAIEmbeddingsRequest; @@ -58,8 +58,8 @@ public class VoyageAIEmbeddingsResponseEntityTests extends ESTestCase { ); assertThat( - ((InferenceTextEmbeddingFloatResults) parsedResults).embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.014539449F, -0.015288644F }))) + ((TextEmbeddingFloatResults) parsedResults).embeddings(), + is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.014539449F, -0.015288644F }))) ); } @@ -103,11 +103,11 @@ public class VoyageAIEmbeddingsResponseEntityTests extends ESTestCase { ); assertThat( - ((InferenceTextEmbeddingFloatResults) parsedResults).embeddings(), + ((TextEmbeddingFloatResults) parsedResults).embeddings(), is( List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.014539449F, -0.015288644F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.0123F, -0.0123F }) + new TextEmbeddingFloatResults.Embedding(new float[] { 0.014539449F, -0.015288644F }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.0123F, -0.0123F }) ) ) ); @@ -291,8 +291,8 @@ public class VoyageAIEmbeddingsResponseEntityTests extends ESTestCase { ); assertThat( - ((InferenceTextEmbeddingFloatResults) parsedResults).embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 1.0F }))) + ((TextEmbeddingFloatResults) parsedResults).embeddings(), + is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 1.0F }))) ); } @@ -327,8 +327,8 @@ public class VoyageAIEmbeddingsResponseEntityTests extends ESTestCase { ); assertThat( - ((InferenceTextEmbeddingFloatResults) parsedResults).embeddings(), - is(List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 4.0294965E10F }))) + ((TextEmbeddingFloatResults) parsedResults).embeddings(), + is(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 4.0294965E10F }))) ); } @@ -416,15 +416,15 @@ public class VoyageAIEmbeddingsResponseEntityTests extends ESTestCase { new HttpResult(mock(HttpResponse.class), response.getBytes(StandardCharsets.UTF_8)) ); - assertThat(parsedResults, instanceOf(InferenceTextEmbeddingFloatResults.class)); + assertThat(parsedResults, instanceOf(TextEmbeddingFloatResults.class)); assertThat( - ((InferenceTextEmbeddingFloatResults) parsedResults).embeddings(), + ((TextEmbeddingFloatResults) parsedResults).embeddings(), is( List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { -0.9F, 0.5F, 0.3F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.1F, 0.5F }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.5F, 0.5F }) + new TextEmbeddingFloatResults.Embedding(new float[] { -0.9F, 0.5F, 0.3F }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.1F, 0.5F }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.5F, 0.5F }) ) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldTests.java index 404713581edd..9eb10cfd9f1a 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldTests.java @@ -21,9 +21,10 @@ import org.elasticsearch.test.AbstractXContentTestCase; import org.elasticsearch.xcontent.XContentParser; import org.elasticsearch.xcontent.XContentParserConfiguration; import org.elasticsearch.xcontent.XContentType; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingByte; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.core.ml.search.WeightedToken; import org.elasticsearch.xpack.core.utils.FloatConversionUtils; import org.elasticsearch.xpack.inference.model.TestModel; @@ -169,50 +170,44 @@ public class SemanticTextFieldTests extends AbstractXContentTestCase inputs) { - List chunks = new ArrayList<>(); + public static ChunkedInferenceEmbedding randomChunkedInferenceEmbeddingByte(Model model, List inputs) { + List chunks = new ArrayList<>(); for (String input : inputs) { byte[] values = new byte[model.getServiceSettings().dimensions()]; for (int j = 0; j < values.length; j++) { values[j] = randomByte(); } - chunks.add( - new ChunkedInferenceEmbeddingByte.ByteEmbeddingChunk(values, input, new ChunkedInference.TextOffset(0, input.length())) - ); + chunks.add(new TextEmbeddingByteResults.Chunk(values, input, new ChunkedInference.TextOffset(0, input.length()))); } - return new ChunkedInferenceEmbeddingByte(chunks); + return new ChunkedInferenceEmbedding(chunks); } - public static ChunkedInferenceEmbeddingFloat randomChunkedInferenceEmbeddingFloat(Model model, List inputs) { - List chunks = new ArrayList<>(); + public static ChunkedInferenceEmbedding randomChunkedInferenceEmbeddingFloat(Model model, List inputs) { + List chunks = new ArrayList<>(); for (String input : inputs) { float[] values = new float[model.getServiceSettings().dimensions()]; for (int j = 0; j < values.length; j++) { values[j] = randomFloat(); } - chunks.add( - new ChunkedInferenceEmbeddingFloat.FloatEmbeddingChunk(values, input, new ChunkedInference.TextOffset(0, input.length())) - ); + chunks.add(new TextEmbeddingFloatResults.Chunk(values, input, new ChunkedInference.TextOffset(0, input.length()))); } - return new ChunkedInferenceEmbeddingFloat(chunks); + return new ChunkedInferenceEmbedding(chunks); } - public static ChunkedInferenceEmbeddingSparse randomChunkedInferenceEmbeddingSparse(List inputs) { + public static ChunkedInferenceEmbedding randomChunkedInferenceEmbeddingSparse(List inputs) { return randomChunkedInferenceEmbeddingSparse(inputs, true); } - public static ChunkedInferenceEmbeddingSparse randomChunkedInferenceEmbeddingSparse(List inputs, boolean withFloats) { - List chunks = new ArrayList<>(); + public static ChunkedInferenceEmbedding randomChunkedInferenceEmbeddingSparse(List inputs, boolean withFloats) { + List chunks = new ArrayList<>(); for (String input : inputs) { var tokens = new ArrayList(); for (var token : input.split("\\s+")) { tokens.add(new WeightedToken(token, withFloats ? randomFloat() : randomIntBetween(1, 255))); } - chunks.add( - new ChunkedInferenceEmbeddingSparse.SparseEmbeddingChunk(tokens, input, new ChunkedInference.TextOffset(0, input.length())) - ); + chunks.add(new SparseEmbeddingResults.Chunk(tokens, input, new ChunkedInference.TextOffset(0, input.length()))); } - return new ChunkedInferenceEmbeddingSparse(chunks); + return new ChunkedInferenceEmbedding(chunks); } public static SemanticTextField randomSemanticText( @@ -302,7 +297,7 @@ public class SemanticTextFieldTests extends AbstractXContentTestCase { - List chunks = new ArrayList<>(); + List chunks = new ArrayList<>(); for (var entry : field.inference().chunks().entrySet()) { String entryField = entry.getKey(); List entryChunks = entry.getValue(); @@ -313,13 +308,13 @@ public class SemanticTextFieldTests extends AbstractXContentTestCase { - List chunks = new ArrayList<>(); + List chunks = new ArrayList<>(); for (var entry : field.inference().chunks().entrySet()) { String entryField = entry.getKey(); List entryChunks = entry.getValue(); @@ -334,16 +329,10 @@ public class SemanticTextFieldTests extends AbstractXContentTestCase throw new AssertionError("Invalid task_type: " + field.inference().modelSettings().taskType().name()); } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/queries/SemanticQueryBuilderTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/queries/SemanticQueryBuilderTests.java index 9a3b4eff1958..451f5fb6ad7b 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/queries/SemanticQueryBuilderTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/queries/SemanticQueryBuilderTests.java @@ -50,8 +50,8 @@ import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xcontent.json.JsonXContent; import org.elasticsearch.xpack.core.XPackClientPlugin; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.core.ml.inference.MlInferenceNamedXContentProvider; import org.elasticsearch.xpack.core.ml.inference.results.MlTextEmbeddingResults; import org.elasticsearch.xpack.core.ml.inference.results.TextExpansionResults; @@ -300,7 +300,7 @@ public class SemanticQueryBuilderTests extends AbstractQueryTestCase { - public static InferenceTextEmbeddingBitResults createRandomResults() { +public class TextEmbeddingBitResultsTests extends AbstractWireSerializingTestCase { + public static TextEmbeddingBitResults createRandomResults() { int embeddings = randomIntBetween(1, 10); - List embeddingResults = new ArrayList<>(embeddings); + List embeddingResults = new ArrayList<>(embeddings); for (int i = 0; i < embeddings; i++) { embeddingResults.add(createRandomEmbedding()); } - return new InferenceTextEmbeddingBitResults(embeddingResults); + return new TextEmbeddingBitResults(embeddingResults); } - private static InferenceByteEmbedding createRandomEmbedding() { + private static TextEmbeddingByteResults.Embedding createRandomEmbedding() { int columns = randomIntBetween(1, 10); byte[] bytes = new byte[columns]; @@ -41,11 +41,11 @@ public class InferenceTextEmbeddingBitResultsTests extends AbstractWireSerializi bytes[i] = randomByte(); } - return new InferenceByteEmbedding(bytes); + return new TextEmbeddingByteResults.Embedding(bytes); } public void testToXContent_CreatesTheRightFormatForASingleEmbedding() throws IOException { - var entity = new InferenceTextEmbeddingBitResults(List.of(new InferenceByteEmbedding(new byte[] { (byte) 23 }))); + var entity = new TextEmbeddingBitResults(List.of(new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 23 }))); String xContentResult = Strings.toString(entity, true, true); assertThat(xContentResult, is(""" @@ -61,8 +61,11 @@ public class InferenceTextEmbeddingBitResultsTests extends AbstractWireSerializi } public void testToXContent_CreatesTheRightFormatForMultipleEmbeddings() throws IOException { - var entity = new InferenceTextEmbeddingBitResults( - List.of(new InferenceByteEmbedding(new byte[] { (byte) 23 }), new InferenceByteEmbedding(new byte[] { (byte) 24 })) + var entity = new TextEmbeddingBitResults( + List.of( + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 23 }), + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 24 }) + ) ); String xContentResult = Strings.toString(entity, true, true); @@ -84,10 +87,10 @@ public class InferenceTextEmbeddingBitResultsTests extends AbstractWireSerializi } public void testTransformToCoordinationFormat() { - var results = new InferenceTextEmbeddingBitResults( + var results = new TextEmbeddingBitResults( List.of( - new InferenceByteEmbedding(new byte[] { (byte) 23, (byte) 24 }), - new InferenceByteEmbedding(new byte[] { (byte) 25, (byte) 26 }) + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 23, (byte) 24 }), + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 25, (byte) 26 }) ) ).transformToCoordinationFormat(); @@ -95,41 +98,41 @@ public class InferenceTextEmbeddingBitResultsTests extends AbstractWireSerializi results, is( List.of( - new MlTextEmbeddingResults(InferenceTextEmbeddingBitResults.TEXT_EMBEDDING_BITS, new double[] { 23F, 24F }, false), - new MlTextEmbeddingResults(InferenceTextEmbeddingBitResults.TEXT_EMBEDDING_BITS, new double[] { 25F, 26F }, false) + new MlTextEmbeddingResults(TextEmbeddingBitResults.TEXT_EMBEDDING_BITS, new double[] { 23F, 24F }, false), + new MlTextEmbeddingResults(TextEmbeddingBitResults.TEXT_EMBEDDING_BITS, new double[] { 25F, 26F }, false) ) ) ); } @Override - protected Writeable.Reader instanceReader() { - return InferenceTextEmbeddingBitResults::new; + protected Writeable.Reader instanceReader() { + return TextEmbeddingBitResults::new; } @Override - protected InferenceTextEmbeddingBitResults createTestInstance() { + protected TextEmbeddingBitResults createTestInstance() { return createRandomResults(); } @Override - protected InferenceTextEmbeddingBitResults mutateInstance(InferenceTextEmbeddingBitResults instance) throws IOException { + protected TextEmbeddingBitResults mutateInstance(TextEmbeddingBitResults instance) throws IOException { // if true we reduce the embeddings list by a random amount, if false we add an embedding to the list if (randomBoolean()) { // -1 to remove at least one item from the list int end = randomInt(instance.embeddings().size() - 1); - return new InferenceTextEmbeddingBitResults(instance.embeddings().subList(0, end)); + return new TextEmbeddingBitResults(instance.embeddings().subList(0, end)); } else { - List embeddings = new ArrayList<>(instance.embeddings()); + List embeddings = new ArrayList<>(instance.embeddings()); embeddings.add(createRandomEmbedding()); - return new InferenceTextEmbeddingBitResults(embeddings); + return new TextEmbeddingBitResults(embeddings); } } public static Map buildExpectationByte(List> embeddings) { return Map.of( - InferenceTextEmbeddingBitResults.TEXT_EMBEDDING_BITS, - embeddings.stream().map(embedding -> Map.of(InferenceByteEmbedding.EMBEDDING, embedding)).toList() + TextEmbeddingBitResults.TEXT_EMBEDDING_BITS, + embeddings.stream().map(embedding -> Map.of(TextEmbeddingByteResults.Embedding.EMBEDDING, embedding)).toList() ); } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/InferenceTextEmbeddingByteResultsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingByteResultsTests.java similarity index 56% rename from x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/InferenceTextEmbeddingByteResultsTests.java rename to x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingByteResultsTests.java index d932f36fb25a..aaa823fda072 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/InferenceTextEmbeddingByteResultsTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingByteResultsTests.java @@ -10,8 +10,7 @@ package org.elasticsearch.xpack.inference.results; import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.test.AbstractWireSerializingTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingByteResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; import org.elasticsearch.xpack.core.ml.inference.results.MlTextEmbeddingResults; import java.io.IOException; @@ -21,19 +20,19 @@ import java.util.Map; import static org.hamcrest.Matchers.is; -public class InferenceTextEmbeddingByteResultsTests extends AbstractWireSerializingTestCase { - public static InferenceTextEmbeddingByteResults createRandomResults() { +public class TextEmbeddingByteResultsTests extends AbstractWireSerializingTestCase { + public static TextEmbeddingByteResults createRandomResults() { int embeddings = randomIntBetween(1, 10); - List embeddingResults = new ArrayList<>(embeddings); + List embeddingResults = new ArrayList<>(embeddings); for (int i = 0; i < embeddings; i++) { embeddingResults.add(createRandomEmbedding()); } - return new InferenceTextEmbeddingByteResults(embeddingResults); + return new TextEmbeddingByteResults(embeddingResults); } - private static InferenceByteEmbedding createRandomEmbedding() { + private static TextEmbeddingByteResults.Embedding createRandomEmbedding() { int columns = randomIntBetween(1, 10); byte[] bytes = new byte[columns]; @@ -41,11 +40,11 @@ public class InferenceTextEmbeddingByteResultsTests extends AbstractWireSerializ bytes[i] = randomByte(); } - return new InferenceByteEmbedding(bytes); + return new TextEmbeddingByteResults.Embedding(bytes); } public void testToXContent_CreatesTheRightFormatForASingleEmbedding() throws IOException { - var entity = new InferenceTextEmbeddingByteResults(List.of(new InferenceByteEmbedding(new byte[] { (byte) 23 }))); + var entity = new TextEmbeddingByteResults(List.of(new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 23 }))); String xContentResult = Strings.toString(entity, true, true); assertThat(xContentResult, is(""" @@ -61,8 +60,11 @@ public class InferenceTextEmbeddingByteResultsTests extends AbstractWireSerializ } public void testToXContent_CreatesTheRightFormatForMultipleEmbeddings() throws IOException { - var entity = new InferenceTextEmbeddingByteResults( - List.of(new InferenceByteEmbedding(new byte[] { (byte) 23 }), new InferenceByteEmbedding(new byte[] { (byte) 24 })) + var entity = new TextEmbeddingByteResults( + List.of( + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 23 }), + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 24 }) + ) ); String xContentResult = Strings.toString(entity, true, true); @@ -84,10 +86,10 @@ public class InferenceTextEmbeddingByteResultsTests extends AbstractWireSerializ } public void testTransformToCoordinationFormat() { - var results = new InferenceTextEmbeddingByteResults( + var results = new TextEmbeddingByteResults( List.of( - new InferenceByteEmbedding(new byte[] { (byte) 23, (byte) 24 }), - new InferenceByteEmbedding(new byte[] { (byte) 25, (byte) 26 }) + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 23, (byte) 24 }), + new TextEmbeddingByteResults.Embedding(new byte[] { (byte) 25, (byte) 26 }) ) ).transformToCoordinationFormat(); @@ -95,41 +97,41 @@ public class InferenceTextEmbeddingByteResultsTests extends AbstractWireSerializ results, is( List.of( - new MlTextEmbeddingResults(InferenceTextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, new double[] { 23F, 24F }, false), - new MlTextEmbeddingResults(InferenceTextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, new double[] { 25F, 26F }, false) + new MlTextEmbeddingResults(TextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, new double[] { 23F, 24F }, false), + new MlTextEmbeddingResults(TextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, new double[] { 25F, 26F }, false) ) ) ); } @Override - protected Writeable.Reader instanceReader() { - return InferenceTextEmbeddingByteResults::new; + protected Writeable.Reader instanceReader() { + return TextEmbeddingByteResults::new; } @Override - protected InferenceTextEmbeddingByteResults createTestInstance() { + protected TextEmbeddingByteResults createTestInstance() { return createRandomResults(); } @Override - protected InferenceTextEmbeddingByteResults mutateInstance(InferenceTextEmbeddingByteResults instance) throws IOException { + protected TextEmbeddingByteResults mutateInstance(TextEmbeddingByteResults instance) throws IOException { // if true we reduce the embeddings list by a random amount, if false we add an embedding to the list if (randomBoolean()) { // -1 to remove at least one item from the list int end = randomInt(instance.embeddings().size() - 1); - return new InferenceTextEmbeddingByteResults(instance.embeddings().subList(0, end)); + return new TextEmbeddingByteResults(instance.embeddings().subList(0, end)); } else { - List embeddings = new ArrayList<>(instance.embeddings()); + List embeddings = new ArrayList<>(instance.embeddings()); embeddings.add(createRandomEmbedding()); - return new InferenceTextEmbeddingByteResults(embeddings); + return new TextEmbeddingByteResults(embeddings); } } public static Map buildExpectationByte(List> embeddings) { return Map.of( - InferenceTextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, - embeddings.stream().map(embedding -> Map.of(InferenceByteEmbedding.EMBEDDING, embedding)).toList() + TextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, + embeddings.stream().map(embedding -> Map.of(TextEmbeddingByteResults.Embedding.EMBEDDING, embedding)).toList() ); } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingResultsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingResultsTests.java index 09b73dc26069..77cbeaea68c3 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingResultsTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/results/TextEmbeddingResultsTests.java @@ -10,9 +10,8 @@ package org.elasticsearch.xpack.inference.results; import org.elasticsearch.common.Strings; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.test.AbstractWireSerializingTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceByteEmbedding; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingByteResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.core.ml.inference.results.MlTextEmbeddingResults; import java.io.IOException; @@ -22,32 +21,30 @@ import java.util.Map; import static org.hamcrest.Matchers.is; -public class TextEmbeddingResultsTests extends AbstractWireSerializingTestCase { - public static InferenceTextEmbeddingFloatResults createRandomResults() { +public class TextEmbeddingResultsTests extends AbstractWireSerializingTestCase { + public static TextEmbeddingFloatResults createRandomResults() { int embeddings = randomIntBetween(1, 10); - List embeddingResults = new ArrayList<>(embeddings); + List embeddingResults = new ArrayList<>(embeddings); for (int i = 0; i < embeddings; i++) { embeddingResults.add(createRandomEmbedding()); } - return new InferenceTextEmbeddingFloatResults(embeddingResults); + return new TextEmbeddingFloatResults(embeddingResults); } - private static InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding createRandomEmbedding() { + private static TextEmbeddingFloatResults.Embedding createRandomEmbedding() { int columns = randomIntBetween(1, 10); float[] floats = new float[columns]; for (int i = 0; i < columns; i++) { floats[i] = randomFloat(); } - return new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(floats); + return new TextEmbeddingFloatResults.Embedding(floats); } public void testToXContent_CreatesTheRightFormatForASingleEmbedding() throws IOException { - var entity = new InferenceTextEmbeddingFloatResults( - List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.1F })) - ); + var entity = new TextEmbeddingFloatResults(List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.1F }))); String xContentResult = Strings.toString(entity, true, true); assertThat(xContentResult, is(""" @@ -63,10 +60,10 @@ public class TextEmbeddingResultsTests extends AbstractWireSerializingTestCase instanceReader() { - return InferenceTextEmbeddingFloatResults::new; + protected Writeable.Reader instanceReader() { + return TextEmbeddingFloatResults::new; } @Override - protected InferenceTextEmbeddingFloatResults createTestInstance() { + protected TextEmbeddingFloatResults createTestInstance() { return createRandomResults(); } @Override - protected InferenceTextEmbeddingFloatResults mutateInstance(InferenceTextEmbeddingFloatResults instance) throws IOException { + protected TextEmbeddingFloatResults mutateInstance(TextEmbeddingFloatResults instance) throws IOException { // if true we reduce the embeddings list by a random amount, if false we add an embedding to the list if (randomBoolean()) { // -1 to remove at least one item from the list int end = randomInt(instance.embeddings().size() - 1); - return new InferenceTextEmbeddingFloatResults(instance.embeddings().subList(0, end)); + return new TextEmbeddingFloatResults(instance.embeddings().subList(0, end)); } else { - List embeddings = new ArrayList<>(instance.embeddings()); + List embeddings = new ArrayList<>(instance.embeddings()); embeddings.add(createRandomEmbedding()); - return new InferenceTextEmbeddingFloatResults(embeddings); + return new TextEmbeddingFloatResults(embeddings); } } public static Map buildExpectationFloat(List embeddings) { - return Map.of( - InferenceTextEmbeddingFloatResults.TEXT_EMBEDDING, - embeddings.stream().map(InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding::new).toList() - ); + return Map.of(TextEmbeddingFloatResults.TEXT_EMBEDDING, embeddings.stream().map(TextEmbeddingFloatResults.Embedding::new).toList()); } public static Map buildExpectationByte(List embeddings) { return Map.of( - InferenceTextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, - embeddings.stream().map(InferenceByteEmbedding::new).toList() + TextEmbeddingByteResults.TEXT_EMBEDDING_BYTES, + embeddings.stream().map(TextEmbeddingByteResults.Embedding::new).toList() ); } public static Map buildExpectationBinary(List embeddings) { - return Map.of("text_embedding_bits", embeddings.stream().map(InferenceByteEmbedding::new).toList()); + return Map.of("text_embedding_bits", embeddings.stream().map(TextEmbeddingByteResults.Embedding::new).toList()); } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ServiceUtilsTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ServiceUtilsTests.java index e3df0f0b5a2e..ddaea0dc3c9a 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ServiceUtilsTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ServiceUtilsTests.java @@ -19,10 +19,10 @@ import org.elasticsearch.inference.InputType; import org.elasticsearch.inference.Model; import org.elasticsearch.inference.TaskType; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingByteResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.core.ml.inference.assignment.AdaptiveAllocationsSettings; -import org.elasticsearch.xpack.inference.results.InferenceTextEmbeddingByteResultsTests; +import org.elasticsearch.xpack.inference.results.TextEmbeddingByteResultsTests; import org.elasticsearch.xpack.inference.results.TextEmbeddingResultsTests; import java.util.EnumSet; @@ -911,7 +911,7 @@ public class ServiceUtilsTests extends ESTestCase { doAnswer(invocation -> { ActionListener listener = invocation.getArgument(7); - listener.onResponse(new InferenceTextEmbeddingFloatResults(List.of())); + listener.onResponse(new TextEmbeddingFloatResults(List.of())); return Void.TYPE; }).when(service).infer(any(), any(), any(), anyBoolean(), any(), any(), any(), any()); @@ -933,7 +933,7 @@ public class ServiceUtilsTests extends ESTestCase { doAnswer(invocation -> { ActionListener listener = invocation.getArgument(7); - listener.onResponse(new InferenceTextEmbeddingByteResults(List.of())); + listener.onResponse(new TextEmbeddingByteResults(List.of())); return Void.TYPE; }).when(service).infer(any(), any(), any(), anyBoolean(), any(), any(), any(), any()); @@ -967,7 +967,7 @@ public class ServiceUtilsTests extends ESTestCase { var size = listener.actionGet(TIMEOUT); - assertThat(size, is(textEmbedding.embeddings().get(0).getSize())); + assertThat(size, is(textEmbedding.embeddings().get(0).values().length)); } public void testGetEmbeddingSize_ReturnsSize_ForTextEmbeddingByteResults() { @@ -976,7 +976,7 @@ public class ServiceUtilsTests extends ESTestCase { var model = mock(Model.class); when(model.getTaskType()).thenReturn(TaskType.TEXT_EMBEDDING); - var textEmbedding = InferenceTextEmbeddingByteResultsTests.createRandomResults(); + var textEmbedding = TextEmbeddingByteResultsTests.createRandomResults(); doAnswer(invocation -> { ActionListener listener = invocation.getArgument(7); @@ -990,7 +990,7 @@ public class ServiceUtilsTests extends ESTestCase { var size = listener.actionGet(TIMEOUT); - assertThat(size, is(textEmbedding.embeddings().get(0).getSize())); + assertThat(size, is(textEmbedding.embeddings().get(0).values().length)); } private static Map modifiableMap(Map aMap) { diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/alibabacloudsearch/AlibabaCloudSearchServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/alibabacloudsearch/AlibabaCloudSearchServiceTests.java index 1ca50d1887ee..c4c6b69b117b 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/alibabacloudsearch/AlibabaCloudSearchServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/alibabacloudsearch/AlibabaCloudSearchServiceTests.java @@ -29,9 +29,9 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.chunking.ChunkingSettingsTests; import org.elasticsearch.xpack.inference.external.action.ExecutableAction; import org.elasticsearch.xpack.inference.external.action.alibabacloudsearch.AlibabaCloudSearchActionVisitor; @@ -43,9 +43,6 @@ import org.elasticsearch.xpack.inference.external.request.alibabacloudsearch.Ali import org.elasticsearch.xpack.inference.logging.ThrottlerManager; import org.elasticsearch.xpack.inference.results.SparseEmbeddingResultsTests; import org.elasticsearch.xpack.inference.services.ServiceFields; -import org.elasticsearch.xpack.inference.services.alibabacloudsearch.completion.AlibabaCloudSearchCompletionModelTests; -import org.elasticsearch.xpack.inference.services.alibabacloudsearch.completion.AlibabaCloudSearchCompletionServiceSettingsTests; -import org.elasticsearch.xpack.inference.services.alibabacloudsearch.completion.AlibabaCloudSearchCompletionTaskSettingsTests; import org.elasticsearch.xpack.inference.services.alibabacloudsearch.embeddings.AlibabaCloudSearchEmbeddingsModel; import org.elasticsearch.xpack.inference.services.alibabacloudsearch.embeddings.AlibabaCloudSearchEmbeddingsModelTests; import org.elasticsearch.xpack.inference.services.alibabacloudsearch.embeddings.AlibabaCloudSearchEmbeddingsServiceSettingsTests; @@ -274,8 +271,8 @@ public class AlibabaCloudSearchServiceTests extends ESTestCase { TimeValue timeout, ActionListener listener ) { - InferenceTextEmbeddingFloatResults results = new InferenceTextEmbeddingFloatResults( - List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { -0.028680f, 0.022033f })) + TextEmbeddingFloatResults results = new TextEmbeddingFloatResults( + List.of(new TextEmbeddingFloatResults.Embedding(new float[] { -0.028680f, 0.022033f })) ); listener.onResponse(results); @@ -380,35 +377,6 @@ public class AlibabaCloudSearchServiceTests extends ESTestCase { testChunkedInfer(TaskType.SPARSE_EMBEDDING, null); } - public void testChunkedInfer_InvalidTaskType() throws IOException { - var senderFactory = HttpRequestSenderTests.createSenderFactory(threadPool, clientManager); - - try (var service = new AlibabaCloudSearchService(senderFactory, createWithEmptySettings(threadPool))) { - var model = AlibabaCloudSearchCompletionModelTests.createModel( - randomAlphaOfLength(10), - TaskType.COMPLETION, - AlibabaCloudSearchCompletionServiceSettingsTests.createRandom(), - AlibabaCloudSearchCompletionTaskSettingsTests.createRandom(), - null - ); - - PlainActionFuture> listener = new PlainActionFuture<>(); - try { - service.chunkedInfer( - model, - null, - List.of("foo", "bar"), - new HashMap<>(), - InputType.INGEST, - InferenceAction.Request.DEFAULT_TIMEOUT, - listener - ); - } catch (Exception e) { - assertThat(e, instanceOf(IllegalArgumentException.class)); - } - } - } - private void testChunkedInfer(TaskType taskType, ChunkingSettings chunkingSettings) throws IOException { var input = List.of("foo", "bar"); @@ -423,12 +391,14 @@ public class AlibabaCloudSearchServiceTests extends ESTestCase { var results = listener.actionGet(TIMEOUT); assertThat(results, instanceOf(List.class)); assertThat(results, hasSize(2)); - var firstResult = results.get(0); - if (TaskType.TEXT_EMBEDDING.equals(taskType)) { - assertThat(firstResult, instanceOf(ChunkedInferenceEmbeddingFloat.class)); - } else if (TaskType.SPARSE_EMBEDDING.equals(taskType)) { - assertThat(firstResult, instanceOf(ChunkedInferenceEmbeddingSparse.class)); - } + var firstResult = results.getFirst(); + assertThat(firstResult, instanceOf(ChunkedInferenceEmbedding.class)); + Class expectedClass = switch (taskType) { + case TEXT_EMBEDDING -> TextEmbeddingFloatResults.Chunk.class; + case SPARSE_EMBEDDING -> SparseEmbeddingResults.Chunk.class; + default -> null; + }; + assertThat(((ChunkedInferenceEmbedding) firstResult).chunks().getFirst(), instanceOf(expectedClass)); } } @@ -552,10 +522,10 @@ public class AlibabaCloudSearchServiceTests extends ESTestCase { ) { public ExecutableAction accept(AlibabaCloudSearchActionVisitor visitor, Map taskSettings, InputType inputType) { return (inferenceInputs, timeout, listener) -> { - InferenceTextEmbeddingFloatResults results = new InferenceTextEmbeddingFloatResults( + TextEmbeddingFloatResults results = new TextEmbeddingFloatResults( List.of( - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.0123f, -0.0123f }), - new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.0456f, -0.0456f }) + new TextEmbeddingFloatResults.Embedding(new float[] { 0.0123f, -0.0123f }), + new TextEmbeddingFloatResults.Embedding(new float[] { 0.0456f, -0.0456f }) ) ); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/amazonbedrock/AmazonBedrockServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/amazonbedrock/AmazonBedrockServiceTests.java index 6505c280c295..970dab45731b 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/amazonbedrock/AmazonBedrockServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/amazonbedrock/AmazonBedrockServiceTests.java @@ -35,8 +35,8 @@ import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; import org.elasticsearch.xpack.core.inference.results.ChatCompletionResults; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.Utils; import org.elasticsearch.xpack.inference.external.amazonbedrock.AmazonBedrockMockRequestSender; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; @@ -965,8 +965,8 @@ public class AmazonBedrockServiceTests extends ESTestCase { try (var service = new AmazonBedrockService(factory, amazonBedrockFactory, createWithEmptySettings(threadPool))) { try (var requestSender = (AmazonBedrockMockRequestSender) amazonBedrockFactory.createSender()) { - var results = new InferenceTextEmbeddingFloatResults( - List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.123F, 0.678F })) + var results = new TextEmbeddingFloatResults( + List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.123F, 0.678F })) ); requestSender.enqueue(results); @@ -1051,8 +1051,8 @@ public class AmazonBedrockServiceTests extends ESTestCase { try (var service = new AmazonBedrockService(factory, amazonBedrockFactory, createWithEmptySettings(threadPool))) { try (var requestSender = (AmazonBedrockMockRequestSender) amazonBedrockFactory.createSender()) { - var results = new InferenceTextEmbeddingFloatResults( - List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.123F, 0.678F })) + var results = new TextEmbeddingFloatResults( + List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.123F, 0.678F })) ); requestSender.enqueue(results); @@ -1110,8 +1110,8 @@ public class AmazonBedrockServiceTests extends ESTestCase { try (var service = new AmazonBedrockService(factory, amazonBedrockFactory, createWithEmptySettings(threadPool))) { try (var requestSender = (AmazonBedrockMockRequestSender) amazonBedrockFactory.createSender()) { - var results = new InferenceTextEmbeddingFloatResults( - List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.123F, 0.678F })) + var results = new TextEmbeddingFloatResults( + List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.123F, 0.678F })) ); requestSender.enqueue(results); @@ -1169,8 +1169,8 @@ public class AmazonBedrockServiceTests extends ESTestCase { try (var service = new AmazonBedrockService(factory, amazonBedrockFactory, createWithEmptySettings(threadPool))) { try (var requestSender = (AmazonBedrockMockRequestSender) amazonBedrockFactory.createSender()) { - var results = new InferenceTextEmbeddingFloatResults( - List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.123F, 0.678F })) + var results = new TextEmbeddingFloatResults( + List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.123F, 0.678F })) ); requestSender.enqueue(results); @@ -1218,8 +1218,8 @@ public class AmazonBedrockServiceTests extends ESTestCase { try (var service = new AmazonBedrockService(factory, amazonBedrockFactory, createWithEmptySettings(threadPool))) { try (var requestSender = (AmazonBedrockMockRequestSender) amazonBedrockFactory.createSender()) { - var results = new InferenceTextEmbeddingFloatResults( - List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.123F, 0.678F })) + var results = new TextEmbeddingFloatResults( + List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.123F, 0.678F })) ); requestSender.enqueue(results); @@ -1428,14 +1428,14 @@ public class AmazonBedrockServiceTests extends ESTestCase { try (var service = new AmazonBedrockService(factory, amazonBedrockFactory, createWithEmptySettings(threadPool))) { try (var requestSender = (AmazonBedrockMockRequestSender) amazonBedrockFactory.createSender()) { { - var mockResults1 = new InferenceTextEmbeddingFloatResults( - List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.123F, 0.678F })) + var mockResults1 = new TextEmbeddingFloatResults( + List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.123F, 0.678F })) ); requestSender.enqueue(mockResults1); } { - var mockResults2 = new InferenceTextEmbeddingFloatResults( - List.of(new InferenceTextEmbeddingFloatResults.InferenceFloatEmbedding(new float[] { 0.223F, 0.278F })) + var mockResults2 = new TextEmbeddingFloatResults( + List.of(new TextEmbeddingFloatResults.Embedding(new float[] { 0.223F, 0.278F })) ); requestSender.enqueue(mockResults2); } @@ -1454,18 +1454,28 @@ public class AmazonBedrockServiceTests extends ESTestCase { var results = listener.actionGet(TIMEOUT); assertThat(results, hasSize(2)); { - assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(0); + assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("abc", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new float[] { 0.123F, 0.678F }, floatResult.chunks().get(0).embedding(), 0.0f); + assertThat(floatResult.chunks().get(0), instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { 0.123F, 0.678F }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding(), + 0.0f + ); } { - assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(1); + assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("xyz", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new float[] { 0.223F, 0.278F }, floatResult.chunks().get(0).embedding(), 0.0f); + assertThat(floatResult.chunks().get(0), instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { 0.223F, 0.278F }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding(), + 0.0f + ); } } } diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/azureaistudio/AzureAiStudioServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/azureaistudio/AzureAiStudioServiceTests.java index cebea7901b95..045789a92bf3 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/azureaistudio/AzureAiStudioServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/azureaistudio/AzureAiStudioServiceTests.java @@ -36,7 +36,8 @@ import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; import org.elasticsearch.xpack.core.inference.results.ChatCompletionResults; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; @@ -1201,18 +1202,28 @@ public class AzureAiStudioServiceTests extends ESTestCase { var results = listener.actionGet(TIMEOUT); assertThat(results, hasSize(2)); { - assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(0); + assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("foo", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new float[] { 0.0123f, -0.0123f }, floatResult.chunks().get(0).embedding(), 0.0f); + assertThat(floatResult.chunks().get(0), instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { 0.0123f, -0.0123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding(), + 0.0f + ); } { - assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(1); + assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("bar", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new float[] { 1.0123f, -1.0123f }, floatResult.chunks().get(0).embedding(), 0.0f); + assertThat(floatResult.chunks().get(0), instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { 1.0123f, -1.0123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding(), + 0.0f + ); } assertThat(webServer.requests(), hasSize(1)); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/azureopenai/AzureOpenAiServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/azureopenai/AzureOpenAiServiceTests.java index e67a5dac0e7c..e58a7049ef87 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/azureopenai/AzureOpenAiServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/azureopenai/AzureOpenAiServiceTests.java @@ -35,7 +35,8 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; @@ -1350,18 +1351,28 @@ public class AzureOpenAiServiceTests extends ESTestCase { var results = listener.actionGet(TIMEOUT); assertThat(results, hasSize(2)); { - assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(0); + assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("foo", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new float[] { 0.123f, -0.123f }, floatResult.chunks().get(0).embedding(), 0.0f); + assertThat(floatResult.chunks().get(0), instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { 0.123f, -0.123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding(), + 0.0f + ); } { - assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(1); + assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("bar", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new float[] { 1.123f, -1.123f }, floatResult.chunks().get(0).embedding(), 0.0f); + assertThat(floatResult.chunks().get(0), instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { 1.123f, -1.123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding(), + 0.0f + ); } assertThat(webServer.requests(), hasSize(1)); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/CohereServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/CohereServiceTests.java index 90e5dc6890c4..8549871d67ff 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/CohereServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/cohere/CohereServiceTests.java @@ -36,8 +36,9 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingByte; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; @@ -1458,18 +1459,26 @@ public class CohereServiceTests extends ESTestCase { var results = listener.actionGet(TIMEOUT); assertThat(results, hasSize(2)); { - assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(0); + assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("foo", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new float[] { 0.123f, -0.123f }, floatResult.chunks().get(0).embedding(), 0.0f); + assertArrayEquals( + new float[] { 0.123f, -0.123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding(), + 0.0f + ); } { - assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(1); + assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("bar", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new float[] { 0.223f, -0.223f }, floatResult.chunks().get(0).embedding(), 0.0f); + assertArrayEquals( + new float[] { 0.223f, -0.223f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding(), + 0.0f + ); } MatcherAssert.assertThat(webServer.requests(), hasSize(1)); @@ -1549,18 +1558,20 @@ public class CohereServiceTests extends ESTestCase { var results = listener.actionGet(TIMEOUT); assertThat(results, hasSize(2)); { - assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingByte.class)); - var floatResult = (ChunkedInferenceEmbeddingByte) results.get(0); - assertThat(floatResult.chunks(), hasSize(1)); - assertEquals("foo", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new byte[] { 23, -23 }, floatResult.chunks().get(0).embedding()); + assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var byteResult = (ChunkedInferenceEmbedding) results.get(0); + assertThat(byteResult.chunks(), hasSize(1)); + assertEquals("foo", byteResult.chunks().get(0).matchedText()); + assertThat(byteResult.chunks().get(0), instanceOf(TextEmbeddingByteResults.Chunk.class)); + assertArrayEquals(new byte[] { 23, -23 }, ((TextEmbeddingByteResults.Chunk) byteResult.chunks().get(0)).embedding()); } { - assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingByte.class)); - var byteResult = (ChunkedInferenceEmbeddingByte) results.get(1); + assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var byteResult = (ChunkedInferenceEmbedding) results.get(1); assertThat(byteResult.chunks(), hasSize(1)); assertEquals("bar", byteResult.chunks().get(0).matchedText()); - assertArrayEquals(new byte[] { 24, -24 }, byteResult.chunks().get(0).embedding()); + assertThat(byteResult.chunks().get(0), instanceOf(TextEmbeddingByteResults.Chunk.class)); + assertArrayEquals(new byte[] { 24, -24 }, ((TextEmbeddingByteResults.Chunk) byteResult.chunks().get(0)).embedding()); } MatcherAssert.assertThat(webServer.requests(), hasSize(1)); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceServiceTests.java index f6d722da3f4e..b3f857990388 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elastic/ElasticInferenceServiceTests.java @@ -36,7 +36,8 @@ import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; import org.elasticsearch.xpack.core.inference.results.UnifiedChatCompletionException; import org.elasticsearch.xpack.core.ml.search.WeightedToken; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; @@ -553,13 +554,13 @@ public class ElasticInferenceServiceTests extends ESTestCase { ); var results = listener.actionGet(TIMEOUT); - assertThat(results.get(0), instanceOf(ChunkedInferenceEmbeddingSparse.class)); - var sparseResult = (ChunkedInferenceEmbeddingSparse) results.get(0); + assertThat(results.get(0), instanceOf(ChunkedInferenceEmbedding.class)); + var sparseResult = (ChunkedInferenceEmbedding) results.get(0); assertThat( sparseResult.chunks(), is( List.of( - new ChunkedInferenceEmbeddingSparse.SparseEmbeddingChunk( + new SparseEmbeddingResults.Chunk( List.of(new WeightedToken("hello", 2.1259406f), new WeightedToken("greet", 1.7073475f)), "input text", new ChunkedInference.TextOffset(0, "input text".length()) diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalServiceTests.java index d1ce79b863c6..e7e654b599fe 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalServiceTests.java @@ -43,9 +43,10 @@ import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.action.util.QueryPage; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceError; +import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.core.ml.MachineLearningField; import org.elasticsearch.xpack.core.ml.action.GetDeploymentStatsAction; import org.elasticsearch.xpack.core.ml.action.GetTrainedModelsAction; @@ -67,7 +68,6 @@ import org.elasticsearch.xpack.core.ml.inference.trainedmodel.TextSimilarityConf import org.elasticsearch.xpack.core.ml.inference.trainedmodel.TokenizationConfigUpdate; import org.elasticsearch.xpack.inference.InferencePlugin; import org.elasticsearch.xpack.inference.chunking.ChunkingSettingsTests; -import org.elasticsearch.xpack.inference.chunking.EmbeddingRequestChunker; import org.elasticsearch.xpack.inference.chunking.WordBoundaryChunkingSettings; import org.elasticsearch.xpack.inference.services.ServiceFields; import org.hamcrest.Matchers; @@ -100,7 +100,6 @@ import static org.elasticsearch.xpack.inference.services.elasticsearch.Elasticse import static org.elasticsearch.xpack.inference.services.elasticsearch.ElasticsearchInternalService.MULTILINGUAL_E5_SMALL_MODEL_ID_LINUX_X86; import static org.elasticsearch.xpack.inference.services.elasticsearch.ElasticsearchInternalService.NAME; import static org.elasticsearch.xpack.inference.services.elasticsearch.ElasticsearchInternalService.OLD_ELSER_SERVICE_NAME; -import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; import static org.hamcrest.Matchers.is; @@ -894,21 +893,23 @@ public class ElasticsearchInternalServiceTests extends ESTestCase { var gotResults = new AtomicBoolean(); var resultsListener = ActionListener.>wrap(chunkedResponse -> { assertThat(chunkedResponse, hasSize(2)); - assertThat(chunkedResponse.get(0), instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var result1 = (ChunkedInferenceEmbeddingFloat) chunkedResponse.get(0); + assertThat(chunkedResponse.get(0), instanceOf(ChunkedInferenceEmbedding.class)); + var result1 = (ChunkedInferenceEmbedding) chunkedResponse.get(0); assertThat(result1.chunks(), hasSize(1)); + assertThat(result1.chunks().get(0), instanceOf(TextEmbeddingFloatResults.Chunk.class)); assertArrayEquals( ((MlTextEmbeddingResults) mlTrainedModelResults.get(0)).getInferenceAsFloat(), - result1.chunks().get(0).embedding(), + ((TextEmbeddingFloatResults.Chunk) result1.chunks().get(0)).embedding(), 0.0001f ); assertEquals("foo", result1.chunks().get(0).matchedText()); - assertThat(chunkedResponse.get(1), instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var result2 = (ChunkedInferenceEmbeddingFloat) chunkedResponse.get(1); + assertThat(chunkedResponse.get(1), instanceOf(ChunkedInferenceEmbedding.class)); + var result2 = (ChunkedInferenceEmbedding) chunkedResponse.get(1); assertThat(result2.chunks(), hasSize(1)); + assertThat(result2.chunks().get(0), instanceOf(TextEmbeddingFloatResults.Chunk.class)); assertArrayEquals( ((MlTextEmbeddingResults) mlTrainedModelResults.get(1)).getInferenceAsFloat(), - result2.chunks().get(0).embedding(), + ((TextEmbeddingFloatResults.Chunk) result2.chunks().get(0)).embedding(), 0.0001f ); assertEquals("bar", result2.chunks().get(0).matchedText()); @@ -969,18 +970,20 @@ public class ElasticsearchInternalServiceTests extends ESTestCase { var resultsListener = ActionListener.>wrap(chunkedResponse -> { assertThat(chunkedResponse, hasSize(2)); - assertThat(chunkedResponse.get(0), instanceOf(ChunkedInferenceEmbeddingSparse.class)); - var result1 = (ChunkedInferenceEmbeddingSparse) chunkedResponse.get(0); + assertThat(chunkedResponse.get(0), instanceOf(ChunkedInferenceEmbedding.class)); + var result1 = (ChunkedInferenceEmbedding) chunkedResponse.get(0); + assertThat(result1.chunks().get(0), instanceOf(SparseEmbeddingResults.Chunk.class)); assertEquals( ((TextExpansionResults) mlTrainedModelResults.get(0)).getWeightedTokens(), - result1.chunks().get(0).weightedTokens() + ((SparseEmbeddingResults.Chunk) result1.chunks().get(0)).weightedTokens() ); assertEquals("foo", result1.chunks().get(0).matchedText()); - assertThat(chunkedResponse.get(1), instanceOf(ChunkedInferenceEmbeddingSparse.class)); - var result2 = (ChunkedInferenceEmbeddingSparse) chunkedResponse.get(1); + assertThat(chunkedResponse.get(1), instanceOf(ChunkedInferenceEmbedding.class)); + var result2 = (ChunkedInferenceEmbedding) chunkedResponse.get(1); + assertThat(result2.chunks().get(0), instanceOf(SparseEmbeddingResults.Chunk.class)); assertEquals( ((TextExpansionResults) mlTrainedModelResults.get(1)).getWeightedTokens(), - result2.chunks().get(0).weightedTokens() + ((SparseEmbeddingResults.Chunk) result2.chunks().get(0)).weightedTokens() ); assertEquals("bar", result2.chunks().get(0).matchedText()); gotResults.set(true); @@ -1039,18 +1042,20 @@ public class ElasticsearchInternalServiceTests extends ESTestCase { var gotResults = new AtomicBoolean(); var resultsListener = ActionListener.>wrap(chunkedResponse -> { assertThat(chunkedResponse, hasSize(2)); - assertThat(chunkedResponse.get(0), instanceOf(ChunkedInferenceEmbeddingSparse.class)); - var result1 = (ChunkedInferenceEmbeddingSparse) chunkedResponse.get(0); + assertThat(chunkedResponse.get(0), instanceOf(ChunkedInferenceEmbedding.class)); + var result1 = (ChunkedInferenceEmbedding) chunkedResponse.get(0); + assertThat(result1.chunks().get(0), instanceOf(SparseEmbeddingResults.Chunk.class)); assertEquals( ((TextExpansionResults) mlTrainedModelResults.get(0)).getWeightedTokens(), - result1.chunks().get(0).weightedTokens() + ((SparseEmbeddingResults.Chunk) result1.chunks().get(0)).weightedTokens() ); assertEquals("foo", result1.chunks().get(0).matchedText()); - assertThat(chunkedResponse.get(1), instanceOf(ChunkedInferenceEmbeddingSparse.class)); - var result2 = (ChunkedInferenceEmbeddingSparse) chunkedResponse.get(1); + assertThat(chunkedResponse.get(1), instanceOf(ChunkedInferenceEmbedding.class)); + var result2 = (ChunkedInferenceEmbedding) chunkedResponse.get(1); + assertThat(result2.chunks().get(0), instanceOf(SparseEmbeddingResults.Chunk.class)); assertEquals( ((TextExpansionResults) mlTrainedModelResults.get(1)).getWeightedTokens(), - result2.chunks().get(0).weightedTokens() + ((SparseEmbeddingResults.Chunk) result2.chunks().get(0)).weightedTokens() ); assertEquals("bar", result2.chunks().get(0).matchedText()); gotResults.set(true); @@ -1219,8 +1224,8 @@ public class ElasticsearchInternalServiceTests extends ESTestCase { var gotResults = new AtomicBoolean(); var resultsListener = ActionListener.>wrap(chunkedResponse -> { assertThat(chunkedResponse, hasSize(1)); - assertThat(chunkedResponse.get(0), instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var sparseResults = (ChunkedInferenceEmbeddingFloat) chunkedResponse.get(0); + assertThat(chunkedResponse.get(0), instanceOf(ChunkedInferenceEmbedding.class)); + var sparseResults = (ChunkedInferenceEmbedding) chunkedResponse.get(0); assertThat(sparseResults.chunks(), hasSize(numChunks)); gotResults.set(true); @@ -1544,41 +1549,6 @@ public class ElasticsearchInternalServiceTests extends ESTestCase { } } - public void testEmbeddingTypeFromTaskTypeAndSettings() { - assertEquals( - EmbeddingRequestChunker.EmbeddingType.SPARSE, - ElasticsearchInternalService.embeddingTypeFromTaskTypeAndSettings( - TaskType.SPARSE_EMBEDDING, - new ElasticsearchInternalServiceSettings(1, 1, "foo", null, null) - ) - ); - assertEquals( - EmbeddingRequestChunker.EmbeddingType.FLOAT, - ElasticsearchInternalService.embeddingTypeFromTaskTypeAndSettings( - TaskType.TEXT_EMBEDDING, - new MultilingualE5SmallInternalServiceSettings(1, 1, "foo", null) - ) - ); - - var e1 = expectThrows( - ElasticsearchStatusException.class, - () -> ElasticsearchInternalService.embeddingTypeFromTaskTypeAndSettings( - TaskType.COMPLETION, - new ElasticsearchInternalServiceSettings(1, 1, "foo", null, null) - ) - ); - assertThat(e1.getMessage(), containsString("Chunking is not supported for task type [completion]")); - - var e2 = expectThrows( - ElasticsearchStatusException.class, - () -> ElasticsearchInternalService.embeddingTypeFromTaskTypeAndSettings( - TaskType.RERANK, - new ElasticsearchInternalServiceSettings(1, 1, "foo", null, null) - ) - ); - assertThat(e2.getMessage(), containsString("Chunking is not supported for task type [rerank]")); - } - public void testIsDefaultId() { var service = createService(mock(Client.class)); assertTrue(service.isDefaultId(".elser-2-elasticsearch")); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/googleaistudio/GoogleAiStudioServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/googleaistudio/GoogleAiStudioServiceTests.java index d0760a583df2..9828a4f21ab5 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/googleaistudio/GoogleAiStudioServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/googleaistudio/GoogleAiStudioServiceTests.java @@ -36,7 +36,8 @@ import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; import org.elasticsearch.xpack.core.inference.results.ChatCompletionResults; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; @@ -877,20 +878,32 @@ public class GoogleAiStudioServiceTests extends ESTestCase { // first result { - assertThat(results.get(0), instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(0); + assertThat(results.get(0), instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); assertEquals(input.get(0), floatResult.chunks().get(0).matchedText()); - assertTrue(Arrays.equals(new float[] { 0.0123f, -0.0123f }, floatResult.chunks().get(0).embedding())); + assertThat(floatResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertTrue( + Arrays.equals( + new float[] { 0.0123f, -0.0123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding() + ) + ); } // second result { - assertThat(results.get(1), instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(1); + assertThat(results.get(1), instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); assertEquals(input.get(1), floatResult.chunks().get(0).matchedText()); - assertTrue(Arrays.equals(new float[] { 0.0456f, -0.0456f }, floatResult.chunks().get(0).embedding())); + assertThat(floatResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertTrue( + Arrays.equals( + new float[] { 0.0456f, -0.0456f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding() + ) + ); } assertThat(webServer.requests(), hasSize(1)); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceElserServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceElserServiceTests.java index 53e7c6c25fd4..1050ac137be8 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceElserServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceElserServiceTests.java @@ -24,7 +24,8 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults; import org.elasticsearch.xpack.core.ml.search.WeightedToken; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; @@ -102,13 +103,13 @@ public class HuggingFaceElserServiceTests extends ESTestCase { ); var result = listener.actionGet(TIMEOUT).get(0); - assertThat(result, instanceOf(ChunkedInferenceEmbeddingSparse.class)); - var sparseResult = (ChunkedInferenceEmbeddingSparse) result; + assertThat(result, instanceOf(ChunkedInferenceEmbedding.class)); + var sparseResult = (ChunkedInferenceEmbedding) result; assertThat( sparseResult.chunks(), is( List.of( - new ChunkedInferenceEmbeddingSparse.SparseEmbeddingChunk( + new SparseEmbeddingResults.Chunk( List.of(new WeightedToken(".", 0.13315596f)), "abc", new ChunkedInference.TextOffset(0, "abc".length()) diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceServiceTests.java index f3137d7011ce..b9e7cda1461c 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/huggingface/HuggingFaceServiceTests.java @@ -34,7 +34,8 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; @@ -783,12 +784,17 @@ public class HuggingFaceServiceTests extends ESTestCase { ); var result = listener.actionGet(TIMEOUT).get(0); - assertThat(result, CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var embeddingResult = (ChunkedInferenceEmbeddingFloat) result; + assertThat(result, CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var embeddingResult = (ChunkedInferenceEmbedding) result; assertThat(embeddingResult.chunks(), hasSize(1)); assertThat(embeddingResult.chunks().get(0).matchedText(), is("abc")); assertThat(embeddingResult.chunks().get(0).offset(), is(new ChunkedInference.TextOffset(0, "abc".length()))); - assertArrayEquals(new float[] { -0.0123f, 0.0123f }, embeddingResult.chunks().get(0).embedding(), 0.001f); + assertThat(embeddingResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { -0.0123f, 0.0123f }, + ((TextEmbeddingFloatResults.Chunk) embeddingResult.chunks().get(0)).embedding(), + 0.001f + ); assertThat(webServer.requests(), hasSize(1)); assertNull(webServer.requests().get(0).getUri().getQuery()); assertThat( @@ -833,11 +839,16 @@ public class HuggingFaceServiceTests extends ESTestCase { var results = listener.actionGet(TIMEOUT); assertThat(results, hasSize(1)); { - assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(0); + assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("abc", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new float[] { 0.123f, -0.123f }, floatResult.chunks().get(0).embedding(), 0.0f); + assertThat(floatResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { 0.123f, -0.123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding(), + 0.0f + ); } assertThat(webServer.requests(), hasSize(1)); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ibmwatsonx/IbmWatsonxServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ibmwatsonx/IbmWatsonxServiceTests.java index 99b7b3868b7f..74d055d44363 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ibmwatsonx/IbmWatsonxServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/ibmwatsonx/IbmWatsonxServiceTests.java @@ -35,7 +35,8 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.common.Truncator; import org.elasticsearch.xpack.inference.external.action.ibmwatsonx.IbmWatsonxActionCreator; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; @@ -729,20 +730,32 @@ public class IbmWatsonxServiceTests extends ESTestCase { // first result { - assertThat(results.get(0), instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(0); + assertThat(results.get(0), instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); assertEquals(input.get(0), floatResult.chunks().get(0).matchedText()); - assertTrue(Arrays.equals(new float[] { 0.0123f, -0.0123f }, floatResult.chunks().get(0).embedding())); + assertThat(floatResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertTrue( + Arrays.equals( + new float[] { 0.0123f, -0.0123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding() + ) + ); } // second result { - assertThat(results.get(1), instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(1); + assertThat(results.get(1), instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); assertEquals(input.get(1), floatResult.chunks().get(0).matchedText()); - assertTrue(Arrays.equals(new float[] { 0.0456f, -0.0456f }, floatResult.chunks().get(0).embedding())); + assertThat(floatResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertTrue( + Arrays.equals( + new float[] { 0.0456f, -0.0456f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding() + ) + ); } assertThat(webServer.requests(), hasSize(1)); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/jinaai/JinaAIServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/jinaai/JinaAIServiceTests.java index 2aeb0447f9c7..3387b8b73978 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/jinaai/JinaAIServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/jinaai/JinaAIServiceTests.java @@ -35,7 +35,8 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; @@ -1797,18 +1798,28 @@ public class JinaAIServiceTests extends ESTestCase { var results = listener.actionGet(TIMEOUT); assertThat(results, hasSize(2)); { - assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(0); + assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("foo", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new float[] { 0.123f, -0.123f }, floatResult.chunks().get(0).embedding(), 0.0f); + assertThat(floatResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { 0.123f, -0.123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding(), + 0.0f + ); } { - assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(1); + assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("bar", floatResult.chunks().get(0).matchedText()); - assertArrayEquals(new float[] { 0.223f, -0.223f }, floatResult.chunks().get(0).embedding(), 0.0f); + assertThat(floatResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { 0.223f, -0.223f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding(), + 0.0f + ); } MatcherAssert.assertThat(webServer.requests(), hasSize(1)); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/mistral/MistralServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/mistral/MistralServiceTests.java index 95ac2cde0e31..6acafd59272e 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/mistral/MistralServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/mistral/MistralServiceTests.java @@ -34,7 +34,8 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.ModelConfigurationsTests; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; @@ -680,16 +681,28 @@ public class MistralServiceTests extends ESTestCase { assertThat(results, hasSize(2)); { - assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(0); + assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); - assertTrue(Arrays.equals(new float[] { 0.123f, -0.123f }, floatResult.chunks().get(0).embedding())); + assertThat(floatResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertTrue( + Arrays.equals( + new float[] { 0.123f, -0.123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding() + ) + ); } { - assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(1); + assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); - assertTrue(Arrays.equals(new float[] { 0.223f, -0.223f }, floatResult.chunks().get(0).embedding())); + assertThat(floatResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertTrue( + Arrays.equals( + new float[] { 0.223f, -0.223f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding() + ) + ); } assertThat(webServer.requests(), hasSize(1)); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/openai/OpenAiServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/openai/OpenAiServiceTests.java index b31cdf4f9d59..13782a538f1f 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/openai/OpenAiServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/openai/OpenAiServiceTests.java @@ -36,7 +36,8 @@ import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.core.inference.results.UnifiedChatCompletionException; import org.elasticsearch.xpack.inference.chunking.ChunkingSettingsTests; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; @@ -1799,18 +1800,30 @@ public class OpenAiServiceTests extends ESTestCase { var results = listener.actionGet(TIMEOUT); assertThat(results, hasSize(2)); { - assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(0); + assertThat(results.get(0), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(0); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("foo", floatResult.chunks().get(0).matchedText()); - assertTrue(Arrays.equals(new float[] { 0.123f, -0.123f }, floatResult.chunks().get(0).embedding())); + assertThat(floatResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertTrue( + Arrays.equals( + new float[] { 0.123f, -0.123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding() + ) + ); } { - assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(1); + assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("bar", floatResult.chunks().get(0).matchedText()); - assertTrue(Arrays.equals(new float[] { 0.223f, -0.223f }, floatResult.chunks().get(0).embedding())); + assertThat(floatResult.chunks().get(0), Matchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertTrue( + Arrays.equals( + new float[] { 0.223f, -0.223f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().get(0)).embedding() + ) + ); } assertThat(webServer.requests(), hasSize(1)); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/validation/TextEmbeddingModelValidatorTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/validation/TextEmbeddingModelValidatorTests.java index d608b4284130..d596d53ba510 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/validation/TextEmbeddingModelValidatorTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/validation/TextEmbeddingModelValidatorTests.java @@ -14,12 +14,12 @@ import org.elasticsearch.inference.InferenceServiceResults; import org.elasticsearch.inference.Model; import org.elasticsearch.inference.ServiceSettings; import org.elasticsearch.test.ESTestCase; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingByteResults; -import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingByteResults; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.EmptyTaskSettingsTests; import org.elasticsearch.xpack.inference.ModelConfigurationsTests; -import org.elasticsearch.xpack.inference.results.InferenceTextEmbeddingByteResultsTests; import org.elasticsearch.xpack.inference.results.SparseEmbeddingResultsTests; +import org.elasticsearch.xpack.inference.results.TextEmbeddingByteResultsTests; import org.junit.Before; import org.mockito.Mock; @@ -89,7 +89,7 @@ public class TextEmbeddingModelValidatorTests extends ESTestCase { } public void testValidate_RetrievingEmbeddingSizeThrowsIllegalStateException() { - InferenceTextEmbeddingFloatResults results = new InferenceTextEmbeddingFloatResults(List.of()); + TextEmbeddingFloatResults results = new TextEmbeddingFloatResults(List.of()); when(mockServiceSettings.dimensionsSetByUser()).thenReturn(true); when(mockServiceSettings.dimensions()).thenReturn(randomNonNegativeInt()); @@ -102,7 +102,7 @@ public class TextEmbeddingModelValidatorTests extends ESTestCase { } public void testValidate_DimensionsSetByUserDoNotEqualEmbeddingSize() { - InferenceTextEmbeddingByteResults results = InferenceTextEmbeddingByteResultsTests.createRandomResults(); + TextEmbeddingByteResults results = TextEmbeddingByteResultsTests.createRandomResults(); var dimensions = randomValueOtherThan(results.getFirstEmbeddingSize(), ESTestCase::randomNonNegativeInt); when(mockServiceSettings.dimensionsSetByUser()).thenReturn(true); @@ -126,7 +126,7 @@ public class TextEmbeddingModelValidatorTests extends ESTestCase { } private void mockSuccessfulValidation(Boolean dimensionsSetByUser) { - InferenceTextEmbeddingByteResults results = InferenceTextEmbeddingByteResultsTests.createRandomResults(); + TextEmbeddingByteResults results = TextEmbeddingByteResultsTests.createRandomResults(); when(mockModel.getConfigurations()).thenReturn(ModelConfigurationsTests.createRandomInstance()); when(mockModel.getTaskSettings()).thenReturn(EmptyTaskSettingsTests.createRandom()); when(mockServiceSettings.dimensionsSetByUser()).thenReturn(dimensionsSetByUser); diff --git a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIServiceTests.java b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIServiceTests.java index d45c78002fa4..6a0428e962f5 100644 --- a/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIServiceTests.java +++ b/x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/voyageai/VoyageAIServiceTests.java @@ -33,7 +33,8 @@ import org.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.xcontent.ToXContent; import org.elasticsearch.xcontent.XContentType; import org.elasticsearch.xpack.core.inference.action.InferenceAction; -import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingFloat; +import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbedding; +import org.elasticsearch.xpack.core.inference.results.TextEmbeddingFloatResults; import org.elasticsearch.xpack.inference.external.http.HttpClientManager; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSender; import org.elasticsearch.xpack.inference.external.http.sender.HttpRequestSenderTests; @@ -1835,18 +1836,28 @@ public class VoyageAIServiceTests extends ESTestCase { var results = listener.actionGet(TIMEOUT); assertThat(results, hasSize(2)); { - assertThat(results.getFirst(), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.getFirst(); + assertThat(results.getFirst(), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.getFirst(); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("foo", floatResult.chunks().getFirst().matchedText()); - assertArrayEquals(new float[] { 0.123f, -0.123f }, floatResult.chunks().getFirst().embedding(), 0.0f); + assertThat(floatResult.chunks().getFirst(), CoreMatchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { 0.123f, -0.123f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().getFirst()).embedding(), + 0.0f + ); } { - assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbeddingFloat.class)); - var floatResult = (ChunkedInferenceEmbeddingFloat) results.get(1); + assertThat(results.get(1), CoreMatchers.instanceOf(ChunkedInferenceEmbedding.class)); + var floatResult = (ChunkedInferenceEmbedding) results.get(1); assertThat(floatResult.chunks(), hasSize(1)); assertEquals("bar", floatResult.chunks().getFirst().matchedText()); - assertArrayEquals(new float[] { 0.223f, -0.223f }, floatResult.chunks().getFirst().embedding(), 0.0f); + assertThat(floatResult.chunks().getFirst(), CoreMatchers.instanceOf(TextEmbeddingFloatResults.Chunk.class)); + assertArrayEquals( + new float[] { 0.223f, -0.223f }, + ((TextEmbeddingFloatResults.Chunk) floatResult.chunks().getFirst()).embedding(), + 0.0f + ); } MatcherAssert.assertThat(webServer.requests(), hasSize(1)); From 5013eee400a87fd6f52b9fa50310ae856d72e629 Mon Sep 17 00:00:00 2001 From: Alexander Spies Date: Fri, 21 Feb 2025 15:41:50 +0100 Subject: [PATCH 07/27] Unmute aaaall the affected tests (#123136) Depends on https://github.com/elastic/elasticsearch/pull/123133 and https://github.com/elastic/elasticsearch/pull/123132 Fixes https://github.com/elastic/elasticsearch/issues/123096 Fixes https://github.com/elastic/elasticsearch/issues/123097 Fixes https://github.com/elastic/elasticsearch/issues/123098 Fixes https://github.com/elastic/elasticsearch/issues/123099 Fixes https://github.com/elastic/elasticsearch/issues/123100 Fixes https://github.com/elastic/elasticsearch/issues/123103 Fixes https://github.com/elastic/elasticsearch/issues/123104 Fixes https://github.com/elastic/elasticsearch/issues/123107 Fixes https://github.com/elastic/elasticsearch/issues/123108 Fixes https://github.com/elastic/elasticsearch/issues/123109 Fixes https://github.com/elastic/elasticsearch/issues/123116 Fixes https://github.com/elastic/elasticsearch/issues/123117 Fixes https://github.com/elastic/elasticsearch/issues/123118 Fixes https://github.com/elastic/elasticsearch/issues/123119 Fixes https://github.com/elastic/elasticsearch/issues/123120 Fixes https://github.com/elastic/elasticsearch/issues/123122 Fixes https://github.com/elastic/elasticsearch/issues/123123 Fixes https://github.com/elastic/elasticsearch/issues/123124 Fixes https://github.com/elastic/elasticsearch/issues/123130 Fixes https://github.com/elastic/elasticsearch/issues/123131 --- muted-tests.yml | 60 ------------------------------------------------- 1 file changed, 60 deletions(-) diff --git a/muted-tests.yml b/muted-tests.yml index 73a2f0c96c80..b1ed5bc53969 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -329,72 +329,12 @@ tests: - class: org.elasticsearch.smoketest.DocsClientYamlTestSuiteIT method: test {yaml=reference/troubleshooting/common-issues/disk-usage-exceeded/line_65} issue: https://github.com/elastic/elasticsearch/issues/123094 -- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT - method: test {fork.ForkWithWhereSortAndLimit ASYNC} - issue: https://github.com/elastic/elasticsearch/issues/123096 -- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT - method: test {fork.ForkWithCommonPrefilter ASYNC} - issue: https://github.com/elastic/elasticsearch/issues/123097 -- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT - method: test {fork.FiveFork SYNC} - issue: https://github.com/elastic/elasticsearch/issues/123098 -- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT - method: test {fork.FiveFork ASYNC} - issue: https://github.com/elastic/elasticsearch/issues/123099 -- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT - method: test {fork.SimpleFork ASYNC} - issue: https://github.com/elastic/elasticsearch/issues/123100 - class: org.elasticsearch.xpack.esql.action.CrossClusterQueryWithPartialResultsIT method: testPartialResults issue: https://github.com/elastic/elasticsearch/issues/123101 -- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT - method: test {fork.ForkWithWhereSortAndLimit SYNC} - issue: https://github.com/elastic/elasticsearch/issues/123103 -- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT - method: test {fork.SimpleFork SYNC} - issue: https://github.com/elastic/elasticsearch/issues/123104 -- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT - method: test {fork.ForkWithWhereSortDescAndLimit SYNC} - issue: https://github.com/elastic/elasticsearch/issues/123107 -- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT - method: test {fork.ForkWithWhereSortDescAndLimit ASYNC} - issue: https://github.com/elastic/elasticsearch/issues/123108 -- class: org.elasticsearch.xpack.esql.qa.mixed.MixedClusterEsqlSpecIT - method: test {fork.ForkWithCommonPrefilter SYNC} - issue: https://github.com/elastic/elasticsearch/issues/123109 -- class: org.elasticsearch.xpack.esql.qa.mixed.EsqlClientYamlIT - method: test {p0=esql/40_tsdb/to_string aggregate_metric_double} - issue: https://github.com/elastic/elasticsearch/issues/123116 -- class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT - method: test {fork.ForkWithCommonPrefilter} - issue: https://github.com/elastic/elasticsearch/issues/123117 -- class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT - method: test {fork.SimpleFork} - issue: https://github.com/elastic/elasticsearch/issues/123118 -- class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT - method: test {fork.FiveFork} - issue: https://github.com/elastic/elasticsearch/issues/123119 -- class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT - method: test {fork.ForkWithWhereSortDescAndLimit} - issue: https://github.com/elastic/elasticsearch/issues/123120 -- class: org.elasticsearch.xpack.esql.qa.mixed.EsqlClientYamlIT - method: test {p0=esql/46_downsample/Render stats from downsampled index} - issue: https://github.com/elastic/elasticsearch/issues/123122 -- class: org.elasticsearch.xpack.esql.qa.mixed.EsqlClientYamlIT - method: test {p0=esql/40_unsupported_types/unsupported} - issue: https://github.com/elastic/elasticsearch/issues/123123 -- class: org.elasticsearch.xpack.esql.qa.mixed.EsqlClientYamlIT - method: test {p0=esql/40_tsdb/render aggregate_metric_double when missing min and max} - issue: https://github.com/elastic/elasticsearch/issues/123124 - class: org.elasticsearch.index.mapper.extras.ScaledFloatFieldMapperTests method: testBlockLoaderFromRowStrideReader issue: https://github.com/elastic/elasticsearch/issues/123126 -- class: org.elasticsearch.xpack.esql.qa.mixed.EsqlClientYamlIT - method: test {p0=esql/40_tsdb/render aggregate_metric_double when missing value} - issue: https://github.com/elastic/elasticsearch/issues/123130 -- class: org.elasticsearch.xpack.esql.ccq.MultiClusterSpecIT - method: test {fork.ForkWithWhereSortAndLimit} - issue: https://github.com/elastic/elasticsearch/issues/123131 - class: org.elasticsearch.index.mapper.extras.ScaledFloatFieldMapperTests method: testBlockLoaderFromRowStrideReaderWithSyntheticSource issue: https://github.com/elastic/elasticsearch/issues/123145 From f044d97ac1c520ff6c35c823a971ae6160bd77fb Mon Sep 17 00:00:00 2001 From: Parker Timmins Date: Fri, 21 Feb 2025 08:46:19 -0600 Subject: [PATCH 08/27] Add lifecycle setting to destination index after adding to data stream (#123071) When reindexing a data stream, remove the lifecycle name setting when creating the destination index, so that ILM does not process it. Add the setting back after adding the destination index to the data stream, at which point ILM can safely process it. --- .../core/security/user/InternalUsers.java | 2 + ...indexDatastreamIndexTransportActionIT.java | 162 +++++++++++++++++- ...ReindexDataStreamIndexTransportAction.java | 2 + ...indexDataStreamPersistentTaskExecutor.java | 36 +++- 4 files changed, 196 insertions(+), 6 deletions(-) diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/InternalUsers.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/InternalUsers.java index 9a0b17b22369..a34c17cfee42 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/InternalUsers.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/user/InternalUsers.java @@ -18,6 +18,7 @@ import org.elasticsearch.action.admin.indices.readonly.TransportAddIndexBlockAct import org.elasticsearch.action.admin.indices.refresh.RefreshAction; import org.elasticsearch.action.admin.indices.rollover.LazyRolloverAction; import org.elasticsearch.action.admin.indices.rollover.RolloverAction; +import org.elasticsearch.action.admin.indices.settings.get.GetSettingsAction; import org.elasticsearch.action.admin.indices.settings.put.TransportUpdateSettingsAction; import org.elasticsearch.action.admin.indices.stats.IndicesStatsAction; import org.elasticsearch.action.bulk.TransportBulkAction; @@ -213,6 +214,7 @@ public class InternalUsers { TransportCloseIndexAction.NAME, TransportCreateIndexAction.TYPE.name(), TransportClusterSearchShardsAction.TYPE.name(), + GetSettingsAction.NAME, TransportUpdateSettingsAction.TYPE.name(), RefreshAction.NAME, ReindexAction.NAME, diff --git a/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java b/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java index 03839b7e05d7..bfb539a514e1 100644 --- a/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java +++ b/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java @@ -23,9 +23,13 @@ import org.elasticsearch.action.admin.indices.template.delete.TransportDeleteInd import org.elasticsearch.action.admin.indices.template.put.TransportPutComposableIndexTemplateAction; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; +import org.elasticsearch.action.datastreams.CreateDataStreamAction; +import org.elasticsearch.action.datastreams.GetDataStreamAction; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.ingest.PutPipelineRequest; import org.elasticsearch.action.ingest.PutPipelineTransportAction; +import org.elasticsearch.action.support.IndicesOptions; +import org.elasticsearch.action.support.master.AcknowledgedRequest; import org.elasticsearch.cluster.block.ClusterBlockException; import org.elasticsearch.cluster.metadata.ComposableIndexTemplate; import org.elasticsearch.cluster.metadata.IndexMetadata; @@ -38,7 +42,9 @@ import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.time.DateFormatter; import org.elasticsearch.common.time.FormatNames; import org.elasticsearch.common.xcontent.support.XContentMapValues; +import org.elasticsearch.core.TimeValue; import org.elasticsearch.datastreams.DataStreamsPlugin; +import org.elasticsearch.index.Index; import org.elasticsearch.index.IndexSettings; import org.elasticsearch.index.mapper.DateFieldMapper; import org.elasticsearch.ingest.common.IngestCommonPlugin; @@ -47,6 +53,18 @@ import org.elasticsearch.reindex.ReindexPlugin; import org.elasticsearch.test.ESIntegTestCase; import org.elasticsearch.test.transport.MockTransportService; import org.elasticsearch.xcontent.XContentType; +import org.elasticsearch.xcontent.json.JsonXContent; +import org.elasticsearch.xpack.core.LocalStateCompositeXPackPlugin; +import org.elasticsearch.xpack.core.ilm.LifecyclePolicy; +import org.elasticsearch.xpack.core.ilm.LifecycleSettings; +import org.elasticsearch.xpack.core.ilm.OperationMode; +import org.elasticsearch.xpack.core.ilm.Phase; +import org.elasticsearch.xpack.core.ilm.StartILMRequest; +import org.elasticsearch.xpack.core.ilm.StopILMRequest; +import org.elasticsearch.xpack.core.ilm.action.GetStatusAction; +import org.elasticsearch.xpack.core.ilm.action.ILMActions; +import org.elasticsearch.xpack.core.ilm.action.PutLifecycleRequest; +import org.elasticsearch.xpack.ilm.IndexLifecycle; import org.elasticsearch.xpack.migrate.MigratePlugin; import org.elasticsearch.xpack.migrate.MigrateTemplateRegistry; import org.junit.Before; @@ -57,6 +75,7 @@ import java.util.Collection; import java.util.List; import java.util.Locale; import java.util.Map; +import java.util.concurrent.TimeUnit; import static java.lang.Boolean.parseBoolean; import static org.elasticsearch.cluster.metadata.MetadataIndexTemplateService.DEFAULT_TIMESTAMP_FIELD; @@ -93,10 +112,22 @@ public class ReindexDatastreamIndexTransportActionIT extends ESIntegTestCase { ReindexPlugin.class, MockTransportService.TestPlugin.class, DataStreamsPlugin.class, - IngestCommonPlugin.class + IngestCommonPlugin.class, + IndexLifecycle.class, + LocalStateCompositeXPackPlugin.class ); } + @Override + protected Settings nodeSettings(int nodeOrdinal, Settings otherSettings) { + return Settings.builder() + .put(super.nodeSettings(nodeOrdinal, otherSettings)) + .put(LifecycleSettings.LIFECYCLE_POLL_INTERVAL, "1s") + // This just generates less churn and makes it easier to read the log file if needed + .put(LifecycleSettings.LIFECYCLE_HISTORY_INDEX_ENABLED, false) + .build(); + } + private static String DATA_STREAM_MAPPING = """ { "dynamic": true, @@ -588,6 +619,135 @@ public class ReindexDatastreamIndexTransportActionIT extends ESIntegTestCase { assertHitCount(prepareSearch(destIndex).setSize(0), 1); } + public void testIndexLifecycleSettingNotCopied() throws Exception { + Map phases = Map.of( + "hot", + new Phase( + "hot", + TimeValue.ZERO, + Map.of( + "rollover", + new org.elasticsearch.xpack.core.ilm.RolloverAction(null, null, null, 1L, null, null, null, null, null, null) + ) + ) + ); + + var policyName = "my-policy"; + LifecyclePolicy policy = new LifecyclePolicy(policyName, phases); + PutLifecycleRequest putLifecycleRequest = new PutLifecycleRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, policy); + assertAcked(client().execute(ILMActions.PUT, putLifecycleRequest).actionGet()); + + // create data stream with a document and wait for ILM to roll it over + var dataStream = createDataStream(policyName); + createDocument(dataStream); + + assertAcked(safeGet(client().execute(ILMActions.START, new StartILMRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)))); + assertBusy(() -> { + var getIndexResponse = safeGet(indicesAdmin().getIndex(new GetIndexRequest(TEST_REQUEST_TIMEOUT).indices(dataStream))); + assertTrue(getIndexResponse.indices().length >= 2); + }); + stopILM(); + + var dataStreams = safeGet( + indicesAdmin().execute( + GetDataStreamAction.INSTANCE, + new GetDataStreamAction.Request(TEST_REQUEST_TIMEOUT, new String[] { dataStream }) + ) + ).getDataStreams(); + + assertFalse(dataStreams.isEmpty()); + String writeIndex = dataStreams.get(0).getDataStream().getWriteIndex().getName(); + List indices = dataStreams.get(0).getDataStream().getIndices().stream().map(Index::getName).toList(); + assertTrue(indices.size() >= 2); + + for (var backingIndex : indices) { + if (backingIndex.equals(writeIndex) == false) { + var destIndex = safeGet( + client().execute(ReindexDataStreamIndexAction.INSTANCE, new ReindexDataStreamIndexAction.Request(backingIndex)) + ).getDestIndex(); + var settingsResponse = safeGet( + indicesAdmin().getSettings(new GetSettingsRequest(TEST_REQUEST_TIMEOUT).indices(backingIndex, destIndex)) + ); + assertEquals(policyName, settingsResponse.getSetting(backingIndex, IndexMetadata.LIFECYCLE_NAME)); + assertNull(settingsResponse.getSetting(destIndex, IndexMetadata.LIFECYCLE_NAME)); + } + } + } + + private void stopILM() throws Exception { + assertAcked(safeGet(client().execute(ILMActions.STOP, new StopILMRequest(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)))); + assertBusy(() -> { + var statusResponse = safeGet( + client().execute(GetStatusAction.INSTANCE, new AcknowledgedRequest.Plain(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT)) + ); + assertEquals(OperationMode.STOPPED, statusResponse.getMode()); + }); + } + + private String createDataStream(String ilmPolicy) throws Exception { + String dataStreamName = randomAlphaOfLength(10).toLowerCase(Locale.getDefault()); + + Settings settings = ilmPolicy != null ? Settings.builder().put(IndexMetadata.LIFECYCLE_NAME, ilmPolicy).build() : null; + + String mapping = """ + { + "properties": { + "@timestamp": { + "type":"date" + }, + "data":{ + "type":"keyword" + } + } + } + """; + Template idxTemplate = new Template(settings, new CompressedXContent(mapping), null); + + ComposableIndexTemplate template = ComposableIndexTemplate.builder() + .indexPatterns(List.of(dataStreamName + "*")) + .template(idxTemplate) + .dataStreamTemplate(new ComposableIndexTemplate.DataStreamTemplate(false, false)) + .build(); + + assertAcked( + client().execute( + TransportPutComposableIndexTemplateAction.TYPE, + new TransportPutComposableIndexTemplateAction.Request(dataStreamName + "_template").indexTemplate(template) + ) + ); + assertAcked( + client().execute( + CreateDataStreamAction.INSTANCE, + new CreateDataStreamAction.Request(TEST_REQUEST_TIMEOUT, TEST_REQUEST_TIMEOUT, dataStreamName) + ) + ); + return dataStreamName; + } + + private long createDocument(String dataStreamName) throws Exception { + // Get some randomized but reasonable timestamps on the data since not all of it is guaranteed to arrive in order. + long timeSeed = System.currentTimeMillis(); + long timestamp = randomLongBetween(timeSeed - TimeUnit.HOURS.toMillis(5), timeSeed); + safeGet( + client().index( + new IndexRequest(dataStreamName).opType(DocWriteRequest.OpType.CREATE) + .source( + JsonXContent.contentBuilder() + .startObject() + .field("@timestamp", timestamp) + .field("data", randomAlphaOfLength(25)) + .endObject() + ) + ) + ); + safeGet( + indicesAdmin().refresh( + new RefreshRequest(".ds-" + dataStreamName + "*").indicesOptions(IndicesOptions.lenientExpandOpenHidden()) + ) + ); + return timestamp; + } + private static void cleanupMetadataBlocks(String index) { var settings = Settings.builder() .putNull(IndexMetadata.SETTING_READ_ONLY) diff --git a/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/ReindexDataStreamIndexTransportAction.java b/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/ReindexDataStreamIndexTransportAction.java index 31fdcbe074c1..2f20290d5804 100644 --- a/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/ReindexDataStreamIndexTransportAction.java +++ b/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/ReindexDataStreamIndexTransportAction.java @@ -254,6 +254,8 @@ public class ReindexDataStreamIndexTransportAction extends HandledTransportActio var settingsOverride = Settings.builder() .put(IndexMetadata.SETTING_NUMBER_OF_REPLICAS, 0) .put(IndexSettings.INDEX_REFRESH_INTERVAL_SETTING.getKey(), -1) + // remove lifecycle so that ILM does not start processing before the index is added to data stream + .putNull(IndexMetadata.LIFECYCLE_NAME) .build(); var request = new CreateIndexFromSourceAction.Request( diff --git a/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/task/ReindexDataStreamPersistentTaskExecutor.java b/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/task/ReindexDataStreamPersistentTaskExecutor.java index 38ab0275f62c..f901e811f70b 100644 --- a/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/task/ReindexDataStreamPersistentTaskExecutor.java +++ b/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/task/ReindexDataStreamPersistentTaskExecutor.java @@ -15,6 +15,10 @@ import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.delete.TransportDeleteIndexAction; import org.elasticsearch.action.admin.indices.rollover.RolloverAction; import org.elasticsearch.action.admin.indices.rollover.RolloverRequest; +import org.elasticsearch.action.admin.indices.settings.get.GetSettingsAction; +import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest; +import org.elasticsearch.action.admin.indices.settings.put.TransportUpdateSettingsAction; +import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest; import org.elasticsearch.action.datastreams.GetDataStreamAction; import org.elasticsearch.action.datastreams.ModifyDataStreamsAction; import org.elasticsearch.action.support.CountDownActionListener; @@ -23,8 +27,10 @@ import org.elasticsearch.action.support.master.AcknowledgedResponse; import org.elasticsearch.client.internal.Client; import org.elasticsearch.cluster.metadata.DataStream; import org.elasticsearch.cluster.metadata.DataStreamAction; +import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.settings.Setting; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.Nullable; import org.elasticsearch.core.TimeValue; import org.elasticsearch.index.Index; @@ -215,9 +221,8 @@ public class ReindexDataStreamPersistentTaskExecutor extends PersistentTasksExec SubscribableListener.newForked( l -> client.execute(ReindexDataStreamIndexAction.INSTANCE, reindexDataStreamIndexRequest, l) ) - .andThen( - (l, result) -> updateDataStream(sourceDataStream, index.getName(), result.getDestIndex(), l, parentTaskId) - ) + .andThen((l, result) -> updateDataStream(sourceDataStream, index.getName(), result.getDestIndex(), l, parentTaskId)) + .andThen((l, newIndex) -> copySettings(index.getName(), newIndex, l, parentTaskId)) .andThen(l -> deleteIndex(index.getName(), parentTaskId, l)) .addListener(ActionListener.wrap(unused -> { reindexDataStreamTask.reindexSucceeded(index.getName()); @@ -234,7 +239,7 @@ public class ReindexDataStreamPersistentTaskExecutor extends PersistentTasksExec String dataStream, String oldIndex, String newIndex, - ActionListener listener, + ActionListener listener, TaskId parentTaskId ) { ModifyDataStreamsAction.Request modifyDataStreamRequest = new ModifyDataStreamsAction.Request( @@ -243,7 +248,28 @@ public class ReindexDataStreamPersistentTaskExecutor extends PersistentTasksExec List.of(DataStreamAction.removeBackingIndex(dataStream, oldIndex), DataStreamAction.addBackingIndex(dataStream, newIndex)) ); modifyDataStreamRequest.setParentTask(parentTaskId); - client.execute(ModifyDataStreamsAction.INSTANCE, modifyDataStreamRequest, listener); + client.execute(ModifyDataStreamsAction.INSTANCE, modifyDataStreamRequest, listener.map(ingored -> newIndex)); + } + + /** + * Copy lifecycle name from the old index to the new index, so that ILM can now process the new index. + * If the new index has a lifecycle name before it is swapped into the data stream, ILM will try, and fail, to process + * the new index. For this reason, lifecycle is not set until after the new index has been added to the data stream. + */ + private void copySettings(String oldIndex, String newIndex, ActionListener listener, TaskId parentTaskId) { + var getSettingsRequest = new GetSettingsRequest(TimeValue.MAX_VALUE).indices(oldIndex); + getSettingsRequest.setParentTask(parentTaskId); + client.execute(GetSettingsAction.INSTANCE, getSettingsRequest, listener.delegateFailure((delegate, response) -> { + String lifecycleName = response.getSetting(oldIndex, IndexMetadata.LIFECYCLE_NAME); + if (lifecycleName != null) { + var settings = Settings.builder().put(IndexMetadata.LIFECYCLE_NAME, lifecycleName).build(); + var updateSettingsRequest = new UpdateSettingsRequest(settings, newIndex); + updateSettingsRequest.setParentTask(parentTaskId); + client.execute(TransportUpdateSettingsAction.TYPE, updateSettingsRequest, delegate); + } else { + delegate.onResponse(null); + } + })); } private void deleteIndex(String indexName, TaskId parentTaskId, ActionListener listener) { From afd7e4e9117090b70b23347426472926eec77096 Mon Sep 17 00:00:00 2001 From: Patrick Doyle <810052+prdoyle@users.noreply.github.com> Date: Fri, 21 Feb 2025 09:54:34 -0500 Subject: [PATCH 09/27] Misc non-java.base file entitlements (#123078) * Misc non-java.base file entitlements * Remove unnecessary dependency --- .../bridge/src/main/java/module-info.java | 1 + .../bridge/EntitlementChecker.java | 28 +++++- .../src/main/java/module-info.java | 1 + .../entitlement/qa/test/FileCheckActions.java | 86 +++++++++++++++++++ .../src/main/java/module-info.java | 5 +- .../api/ElasticsearchEntitlementChecker.java | 73 ++++++++++++++++ .../runtime/policy/PolicyManager.java | 4 + 7 files changed, 195 insertions(+), 3 deletions(-) diff --git a/libs/entitlement/bridge/src/main/java/module-info.java b/libs/entitlement/bridge/src/main/java/module-info.java index 518a0a1ef29e..6a85013c1f1f 100644 --- a/libs/entitlement/bridge/src/main/java/module-info.java +++ b/libs/entitlement/bridge/src/main/java/module-info.java @@ -12,6 +12,7 @@ module org.elasticsearch.entitlement.bridge { requires java.net.http; requires jdk.net; + requires java.logging; exports org.elasticsearch.entitlement.bridge; } diff --git a/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java b/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java index f0bbcd9b7d09..ce162abed60c 100644 --- a/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java +++ b/libs/entitlement/bridge/src/main/java/org/elasticsearch/entitlement/bridge/EntitlementChecker.java @@ -88,6 +88,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; import java.util.function.BiPredicate; import java.util.function.Consumer; +import java.util.logging.FileHandler; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; @@ -882,9 +883,34 @@ public interface EntitlementChecker { void check$java_nio_file_Files$$lines(Class callerClass, Path path); - // file system providers void check$java_nio_file_spi_FileSystemProvider$(Class callerClass); + void check$java_util_logging_FileHandler$(Class callerClass); + + void check$java_util_logging_FileHandler$(Class callerClass, String pattern); + + void check$java_util_logging_FileHandler$(Class callerClass, String pattern, boolean append); + + void check$java_util_logging_FileHandler$(Class callerClass, String pattern, int limit, int count); + + void check$java_util_logging_FileHandler$(Class callerClass, String pattern, int limit, int count, boolean append); + + void check$java_util_logging_FileHandler$(Class callerClass, String pattern, long limit, int count, boolean append); + + void check$java_util_logging_FileHandler$close(Class callerClass, FileHandler that); + + void check$java_net_http_HttpRequest$BodyPublishers$$ofFile(Class callerClass, Path path); + + void check$java_net_http_HttpResponse$BodyHandlers$$ofFile(Class callerClass, Path path); + + void check$java_net_http_HttpResponse$BodyHandlers$$ofFile(Class callerClass, Path path, OpenOption... options); + + void check$java_net_http_HttpResponse$BodyHandlers$$ofFileDownload(Class callerClass, Path directory, OpenOption... openOptions); + + void check$java_net_http_HttpResponse$BodySubscribers$$ofFile(Class callerClass, Path directory); + + void check$java_net_http_HttpResponse$BodySubscribers$$ofFile(Class callerClass, Path directory, OpenOption... openOptions); + void checkNewFileSystem(Class callerClass, FileSystemProvider that, URI uri, Map env); void checkNewFileSystem(Class callerClass, FileSystemProvider that, Path path, Map env); diff --git a/libs/entitlement/qa/entitled-plugin/src/main/java/module-info.java b/libs/entitlement/qa/entitled-plugin/src/main/java/module-info.java index eafac9006dae..74559a12a4da 100644 --- a/libs/entitlement/qa/entitled-plugin/src/main/java/module-info.java +++ b/libs/entitlement/qa/entitled-plugin/src/main/java/module-info.java @@ -12,6 +12,7 @@ module org.elasticsearch.entitlement.qa.entitled { requires org.elasticsearch.entitlement; requires org.elasticsearch.base; // SuppressForbidden requires org.elasticsearch.logging; + requires java.logging; exports org.elasticsearch.entitlement.qa.entitled; // Must be unqualified so non-modular IT tests can call us } diff --git a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java index d62fbf458be0..b22643c90064 100644 --- a/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java +++ b/libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/FileCheckActions.java @@ -22,6 +22,8 @@ import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.RandomAccessFile; +import java.net.http.HttpRequest; +import java.net.http.HttpResponse; import java.nio.charset.StandardCharsets; import java.nio.file.Path; import java.nio.file.Paths; @@ -29,10 +31,13 @@ import java.security.GeneralSecurityException; import java.security.KeyStore; import java.util.Scanner; import java.util.jar.JarFile; +import java.util.logging.FileHandler; import java.util.zip.ZipException; import java.util.zip.ZipFile; import static java.nio.charset.Charset.defaultCharset; +import static java.nio.file.StandardOpenOption.CREATE; +import static java.nio.file.StandardOpenOption.WRITE; import static java.util.zip.ZipFile.OPEN_DELETE; import static java.util.zip.ZipFile.OPEN_READ; import static org.elasticsearch.entitlement.qa.entitled.EntitledActions.createTempFileForWrite; @@ -477,5 +482,86 @@ class FileCheckActions { new Scanner(readFile().toFile(), "UTF-8"); } + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void fileHandler() throws IOException { + new FileHandler(); + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void fileHandler_String() throws IOException { + new FileHandler(readFile().toString()); + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void fileHandler_StringBoolean() throws IOException { + new FileHandler(readFile().toString(), false); + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void fileHandler_StringIntInt() throws IOException { + new FileHandler(readFile().toString(), 1, 2); + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void fileHandler_StringIntIntBoolean() throws IOException { + new FileHandler(readFile().toString(), 1, 2, false); + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void fileHandler_StringLongIntBoolean() throws IOException { + new FileHandler(readFile().toString(), 1L, 2, false); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void httpRequestBodyPublishersOfFile() throws IOException { + HttpRequest.BodyPublishers.ofFile(readFile()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void httpResponseBodyHandlersOfFile() { + HttpResponse.BodyHandlers.ofFile(readWriteFile()); + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void httpResponseBodyHandlersOfFile_readOnly() { + HttpResponse.BodyHandlers.ofFile(readFile()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void httpResponseBodyHandlersOfFileDownload() { + HttpResponse.BodyHandlers.ofFileDownload(readWriteDir()); + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void httpResponseBodyHandlersOfFileDownload_readOnly() { + HttpResponse.BodyHandlers.ofFileDownload(readDir()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void httpResponseBodySubscribersOfFile_File() { + HttpResponse.BodySubscribers.ofFile(readWriteFile()); + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void httpResponseBodySubscribersOfFile_File_readOnly() { + HttpResponse.BodySubscribers.ofFile(readFile()); + } + + @EntitlementTest(expectedAccess = PLUGINS) + static void httpResponseBodySubscribersOfFile_FileOpenOptions() { + // Note that, unlike other methods like BodyHandlers.ofFile, this is indeed + // an overload distinct from ofFile with no OpenOptions, and so it needs its + // own instrumentation and its own test. + HttpResponse.BodySubscribers.ofFile(readWriteFile(), CREATE, WRITE); + } + + @EntitlementTest(expectedAccess = ALWAYS_DENIED) + static void httpResponseBodySubscribersOfFile_FileOpenOptions_readOnly() { + // Note that, unlike other methods like BodyHandlers.ofFile, this is indeed + // an overload distinct from ofFile with no OpenOptions, and so it needs its + // own instrumentation and its own test. + HttpResponse.BodySubscribers.ofFile(readFile(), CREATE, WRITE); + } + private FileCheckActions() {} } diff --git a/libs/entitlement/src/main/java/module-info.java b/libs/entitlement/src/main/java/module-info.java index 697d26747b80..d6737a14a0b8 100644 --- a/libs/entitlement/src/main/java/module-info.java +++ b/libs/entitlement/src/main/java/module-info.java @@ -8,12 +8,13 @@ */ module org.elasticsearch.entitlement { + requires org.elasticsearch.base; requires org.elasticsearch.xcontent; requires org.elasticsearch.logging; requires java.instrument; - requires org.elasticsearch.base; - requires jdk.attach; + requires java.logging; requires java.net.http; + requires jdk.attach; requires jdk.net; requires static org.elasticsearch.entitlement.bridge; // At runtime, this will be in java.base diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java index f6a45cce3c56..028d03056724 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/api/ElasticsearchEntitlementChecker.java @@ -97,6 +97,7 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.ForkJoinPool; import java.util.function.BiPredicate; import java.util.function.Consumer; +import java.util.logging.FileHandler; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.HttpsURLConnection; @@ -1845,6 +1846,78 @@ public class ElasticsearchEntitlementChecker implements EntitlementChecker { policyManager.checkChangeJVMGlobalState(callerClass); } + @Override + public void check$java_util_logging_FileHandler$(Class callerClass) { + policyManager.checkLoggingFileHandler(callerClass); + } + + @Override + public void check$java_util_logging_FileHandler$(Class callerClass, String pattern) { + policyManager.checkLoggingFileHandler(callerClass); + } + + @Override + public void check$java_util_logging_FileHandler$(Class callerClass, String pattern, boolean append) { + policyManager.checkLoggingFileHandler(callerClass); + } + + @Override + public void check$java_util_logging_FileHandler$(Class callerClass, String pattern, int limit, int count) { + policyManager.checkLoggingFileHandler(callerClass); + } + + @Override + public void check$java_util_logging_FileHandler$(Class callerClass, String pattern, int limit, int count, boolean append) { + policyManager.checkLoggingFileHandler(callerClass); + } + + @Override + public void check$java_util_logging_FileHandler$(Class callerClass, String pattern, long limit, int count, boolean append) { + policyManager.checkLoggingFileHandler(callerClass); + } + + @Override + public void check$java_util_logging_FileHandler$close(Class callerClass, FileHandler that) { + // Note that there's no IT test for this one, because there's no way to create + // a FileHandler. However, we have this check just in case someone does manage + // to get their hands on a FileHandler and uses close() to cause its lock file to be deleted. + policyManager.checkLoggingFileHandler(callerClass); + } + + @Override + public void check$java_net_http_HttpRequest$BodyPublishers$$ofFile(Class callerClass, Path path) { + policyManager.checkFileRead(callerClass, path); + } + + @Override + public void check$java_net_http_HttpResponse$BodyHandlers$$ofFile(Class callerClass, Path path) { + policyManager.checkFileWrite(callerClass, path); + } + + @Override + public void check$java_net_http_HttpResponse$BodyHandlers$$ofFile(Class callerClass, Path path, OpenOption... options) { + policyManager.checkFileWrite(callerClass, path); + } + + @Override + public void check$java_net_http_HttpResponse$BodyHandlers$$ofFileDownload( + Class callerClass, + Path directory, + OpenOption... openOptions + ) { + policyManager.checkFileWrite(callerClass, directory); + } + + @Override + public void check$java_net_http_HttpResponse$BodySubscribers$$ofFile(Class callerClass, Path directory) { + policyManager.checkFileWrite(callerClass, directory); + } + + @Override + public void check$java_net_http_HttpResponse$BodySubscribers$$ofFile(Class callerClass, Path directory, OpenOption... openOptions) { + policyManager.checkFileWrite(callerClass, directory); + } + @Override public void checkNewFileSystem(Class callerClass, FileSystemProvider that, URI uri, Map env) { policyManager.checkChangeJVMGlobalState(callerClass); diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java index 66e44576b745..2aafcfc594ab 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java @@ -240,6 +240,10 @@ public class PolicyManager { neverEntitled(callerClass, () -> walkStackForCheckMethodName().orElse("change JVM global state")); } + public void checkLoggingFileHandler(Class callerClass) { + neverEntitled(callerClass, () -> walkStackForCheckMethodName().orElse("create logging file handler")); + } + private Optional walkStackForCheckMethodName() { // Look up the check$ method to compose an informative error message. // This way, we don't need to painstakingly describe every individual global-state change. From 21845ad7a18821ccd80927211285308bb3eb8038 Mon Sep 17 00:00:00 2001 From: Costin Leau Date: Fri, 21 Feb 2025 06:56:09 -0800 Subject: [PATCH 10/27] ESQL: Remove duplicated nested commands (#123085) Fork grammar duplicated nested command declaration causing additional lexing to occur resulting in invalid field name declaration Relates to #121948 --- docs/changelog/123085.yaml | 5 + .../esql/src/main/antlr/EsqlBaseLexer.g4 | 9 +- .../esql/src/main/antlr/EsqlBaseLexer.tokens | 99 +- .../esql/src/main/antlr/EsqlBaseParser.tokens | 99 +- .../xpack/esql/parser/EsqlBaseLexer.interp | 17 +- .../xpack/esql/parser/EsqlBaseLexer.java | 2184 ++++++++--------- .../xpack/esql/parser/EsqlBaseParser.interp | 10 +- .../xpack/esql/parser/EsqlBaseParser.java | 128 +- .../esql/parser/StatementParserTests.java | 23 +- 9 files changed, 1282 insertions(+), 1292 deletions(-) create mode 100644 docs/changelog/123085.yaml diff --git a/docs/changelog/123085.yaml b/docs/changelog/123085.yaml new file mode 100644 index 000000000000..316b1f6f2670 --- /dev/null +++ b/docs/changelog/123085.yaml @@ -0,0 +1,5 @@ +pr: 123085 +summary: Remove duplicated nested commands +area: ES|QL +type: bug +issues: [] diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 index 6556cbba5c5f..ed49ffdef8ae 100644 --- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 +++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.g4 @@ -195,14 +195,12 @@ IN: 'in'; IS: 'is'; LAST : 'last'; LIKE: 'like'; -LP : '('; NOT : 'not'; NULL : 'null'; NULLS : 'nulls'; OR : 'or'; PARAM: '?'; RLIKE: 'rlike'; -RP : ')'; TRUE : 'true'; EQ : '=='; @@ -223,8 +221,6 @@ LEFT_BRACES : '{'; RIGHT_BRACES : '}'; NESTED_WHERE : WHERE -> type(WHERE); -NESTED_SORT : {this.isDevVersion()}? SORT -> type(SORT); -NESTED_LIMIT : {this.isDevVersion()}? LIMIT -> type(LIMIT); NAMED_OR_POSITIONAL_PARAM : PARAM (LETTER | UNDERSCORE) UNQUOTED_ID_BODY* @@ -239,6 +235,9 @@ NAMED_OR_POSITIONAL_PARAM OPENING_BRACKET : '[' -> pushMode(EXPRESSION_MODE), pushMode(EXPRESSION_MODE); CLOSING_BRACKET : ']' -> popMode, popMode; +LP : '(' -> pushMode(EXPRESSION_MODE), pushMode(EXPRESSION_MODE); +RP : ')' -> popMode, popMode; + UNQUOTED_IDENTIFIER : LETTER UNQUOTED_ID_BODY* // only allow @ at beginning of identifier to keep the option to allow @ as infix operator in the future @@ -678,8 +677,8 @@ INSIST_MULTILINE_COMMENT : MULTILINE_COMMENT -> channel(HIDDEN); // mode FORK_MODE; FORK_LP : LP -> type(LP), pushMode(DEFAULT_MODE); -FORK_RP : RP -> type(RP), popMode; FORK_PIPE : PIPE -> type(PIPE), popMode; + FORK_WS : WS -> channel(HIDDEN); FORK_LINE_COMMENT : LINE_COMMENT -> channel(HIDDEN); FORK_MULTILINE_COMMENT : MULTILINE_COMMENT -> channel(HIDDEN); diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens index 7756d406adee..2ea8b6892293 100644 --- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens +++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseLexer.tokens @@ -47,32 +47,32 @@ IN=46 IS=47 LAST=48 LIKE=49 -LP=50 -NOT=51 -NULL=52 -NULLS=53 -OR=54 -PARAM=55 -RLIKE=56 -RP=57 -TRUE=58 -EQ=59 -CIEQ=60 -NEQ=61 -LT=62 -LTE=63 -GT=64 -GTE=65 -PLUS=66 -MINUS=67 -ASTERISK=68 -SLASH=69 -PERCENT=70 -LEFT_BRACES=71 -RIGHT_BRACES=72 -NAMED_OR_POSITIONAL_PARAM=73 -OPENING_BRACKET=74 -CLOSING_BRACKET=75 +NOT=50 +NULL=51 +NULLS=52 +OR=53 +PARAM=54 +RLIKE=55 +TRUE=56 +EQ=57 +CIEQ=58 +NEQ=59 +LT=60 +LTE=61 +GT=62 +GTE=63 +PLUS=64 +MINUS=65 +ASTERISK=66 +SLASH=67 +PERCENT=68 +LEFT_BRACES=69 +RIGHT_BRACES=70 +NAMED_OR_POSITIONAL_PARAM=71 +OPENING_BRACKET=72 +CLOSING_BRACKET=73 +LP=74 +RP=75 UNQUOTED_IDENTIFIER=76 QUOTED_IDENTIFIER=77 EXPR_LINE_COMMENT=78 @@ -173,30 +173,29 @@ FORK_MULTILINE_COMMENT=142 'is'=47 'last'=48 'like'=49 -'('=50 -'not'=51 -'null'=52 -'nulls'=53 -'or'=54 -'?'=55 -'rlike'=56 -')'=57 -'true'=58 -'=='=59 -'=~'=60 -'!='=61 -'<'=62 -'<='=63 -'>'=64 -'>='=65 -'+'=66 -'-'=67 -'*'=68 -'/'=69 -'%'=70 -'{'=71 -'}'=72 -']'=75 +'not'=50 +'null'=51 +'nulls'=52 +'or'=53 +'?'=54 +'rlike'=55 +'true'=56 +'=='=57 +'=~'=58 +'!='=59 +'<'=60 +'<='=61 +'>'=62 +'>='=63 +'+'=64 +'-'=65 +'*'=66 +'/'=67 +'%'=68 +'{'=69 +'}'=70 +']'=73 +')'=75 'metadata'=84 'as'=93 'on'=97 diff --git a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens index 7756d406adee..2ea8b6892293 100644 --- a/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens +++ b/x-pack/plugin/esql/src/main/antlr/EsqlBaseParser.tokens @@ -47,32 +47,32 @@ IN=46 IS=47 LAST=48 LIKE=49 -LP=50 -NOT=51 -NULL=52 -NULLS=53 -OR=54 -PARAM=55 -RLIKE=56 -RP=57 -TRUE=58 -EQ=59 -CIEQ=60 -NEQ=61 -LT=62 -LTE=63 -GT=64 -GTE=65 -PLUS=66 -MINUS=67 -ASTERISK=68 -SLASH=69 -PERCENT=70 -LEFT_BRACES=71 -RIGHT_BRACES=72 -NAMED_OR_POSITIONAL_PARAM=73 -OPENING_BRACKET=74 -CLOSING_BRACKET=75 +NOT=50 +NULL=51 +NULLS=52 +OR=53 +PARAM=54 +RLIKE=55 +TRUE=56 +EQ=57 +CIEQ=58 +NEQ=59 +LT=60 +LTE=61 +GT=62 +GTE=63 +PLUS=64 +MINUS=65 +ASTERISK=66 +SLASH=67 +PERCENT=68 +LEFT_BRACES=69 +RIGHT_BRACES=70 +NAMED_OR_POSITIONAL_PARAM=71 +OPENING_BRACKET=72 +CLOSING_BRACKET=73 +LP=74 +RP=75 UNQUOTED_IDENTIFIER=76 QUOTED_IDENTIFIER=77 EXPR_LINE_COMMENT=78 @@ -173,30 +173,29 @@ FORK_MULTILINE_COMMENT=142 'is'=47 'last'=48 'like'=49 -'('=50 -'not'=51 -'null'=52 -'nulls'=53 -'or'=54 -'?'=55 -'rlike'=56 -')'=57 -'true'=58 -'=='=59 -'=~'=60 -'!='=61 -'<'=62 -'<='=63 -'>'=64 -'>='=65 -'+'=66 -'-'=67 -'*'=68 -'/'=69 -'%'=70 -'{'=71 -'}'=72 -']'=75 +'not'=50 +'null'=51 +'nulls'=52 +'or'=53 +'?'=54 +'rlike'=55 +'true'=56 +'=='=57 +'=~'=58 +'!='=59 +'<'=60 +'<='=61 +'>'=62 +'>='=63 +'+'=64 +'-'=65 +'*'=66 +'/'=67 +'%'=68 +'{'=69 +'}'=70 +']'=73 +')'=75 'metadata'=84 'as'=93 'on'=97 diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp index 3f1b0baf6808..f2afedee8ac0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.interp @@ -49,14 +49,12 @@ null 'is' 'last' 'like' -'(' 'not' 'null' 'nulls' 'or' '?' 'rlike' -')' 'true' '==' '=~' @@ -76,6 +74,8 @@ null null ']' null +')' +null null null null @@ -194,14 +194,12 @@ IN IS LAST LIKE -LP NOT NULL NULLS OR PARAM RLIKE -RP TRUE EQ CIEQ @@ -220,6 +218,8 @@ RIGHT_BRACES NAMED_OR_POSITIONAL_PARAM OPENING_BRACKET CLOSING_BRACKET +LP +RP UNQUOTED_IDENTIFIER QUOTED_IDENTIFIER EXPR_LINE_COMMENT @@ -348,14 +348,12 @@ IN IS LAST LIKE -LP NOT NULL NULLS OR PARAM RLIKE -RP TRUE EQ CIEQ @@ -372,11 +370,11 @@ PERCENT LEFT_BRACES RIGHT_BRACES NESTED_WHERE -NESTED_SORT -NESTED_LIMIT NAMED_OR_POSITIONAL_PARAM OPENING_BRACKET CLOSING_BRACKET +LP +RP UNQUOTED_IDENTIFIER QUOTED_ID QUOTED_IDENTIFIER @@ -527,7 +525,6 @@ INSIST_WS INSIST_LINE_COMMENT INSIST_MULTILINE_COMMENT FORK_LP -FORK_RP FORK_PIPE FORK_WS FORK_LINE_COMMENT @@ -559,4 +556,4 @@ INSIST_MODE FORK_MODE atn: -[4, 0, 142, 1799, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153, 7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157, 2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162, 7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166, 2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171, 7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175, 2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180, 7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184, 2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 2, 189, 7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193, 2, 194, 7, 194, 2, 195, 7, 195, 2, 196, 7, 196, 2, 197, 7, 197, 2, 198, 7, 198, 2, 199, 7, 199, 2, 200, 7, 200, 2, 201, 7, 201, 2, 202, 7, 202, 2, 203, 7, 203, 2, 204, 7, 204, 2, 205, 7, 205, 2, 206, 7, 206, 2, 207, 7, 207, 2, 208, 7, 208, 2, 209, 7, 209, 2, 210, 7, 210, 2, 211, 7, 211, 2, 212, 7, 212, 2, 213, 7, 213, 2, 214, 7, 214, 2, 215, 7, 215, 2, 216, 7, 216, 2, 217, 7, 217, 2, 218, 7, 218, 2, 219, 7, 219, 2, 220, 7, 220, 2, 221, 7, 221, 2, 222, 7, 222, 2, 223, 7, 223, 2, 224, 7, 224, 2, 225, 7, 225, 2, 226, 7, 226, 2, 227, 7, 227, 2, 228, 7, 228, 2, 229, 7, 229, 2, 230, 7, 230, 2, 231, 7, 231, 2, 232, 7, 232, 2, 233, 7, 233, 2, 234, 7, 234, 2, 235, 7, 235, 2, 236, 7, 236, 2, 237, 7, 237, 2, 238, 7, 238, 2, 239, 7, 239, 2, 240, 7, 240, 2, 241, 7, 241, 2, 242, 7, 242, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 4, 26, 744, 8, 26, 11, 26, 12, 26, 745, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 5, 27, 754, 8, 27, 10, 27, 12, 27, 757, 9, 27, 1, 27, 3, 27, 760, 8, 27, 1, 27, 3, 27, 763, 8, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 5, 28, 772, 8, 28, 10, 28, 12, 28, 775, 9, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 4, 29, 783, 8, 29, 11, 29, 12, 29, 784, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 3, 35, 804, 8, 35, 1, 35, 4, 35, 807, 8, 35, 11, 35, 12, 35, 808, 1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 3, 38, 818, 8, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 3, 40, 825, 8, 40, 1, 41, 1, 41, 1, 41, 5, 41, 830, 8, 41, 10, 41, 12, 41, 833, 9, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 5, 41, 841, 8, 41, 10, 41, 12, 41, 844, 9, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 3, 41, 851, 8, 41, 1, 41, 3, 41, 854, 8, 41, 3, 41, 856, 8, 41, 1, 42, 4, 42, 859, 8, 42, 11, 42, 12, 42, 860, 1, 43, 4, 43, 864, 8, 43, 11, 43, 12, 43, 865, 1, 43, 1, 43, 5, 43, 870, 8, 43, 10, 43, 12, 43, 873, 9, 43, 1, 43, 1, 43, 4, 43, 877, 8, 43, 11, 43, 12, 43, 878, 1, 43, 4, 43, 882, 8, 43, 11, 43, 12, 43, 883, 1, 43, 1, 43, 5, 43, 888, 8, 43, 10, 43, 12, 43, 891, 9, 43, 3, 43, 893, 8, 43, 1, 43, 1, 43, 1, 43, 1, 43, 4, 43, 899, 8, 43, 11, 43, 12, 43, 900, 1, 43, 1, 43, 3, 43, 905, 8, 43, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 63, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 74, 1, 74, 1, 74, 1, 75, 1, 75, 1, 76, 1, 76, 1, 77, 1, 77, 1, 78, 1, 78, 1, 79, 1, 79, 1, 80, 1, 80, 1, 81, 1, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 3, 85, 1047, 8, 85, 1, 85, 5, 85, 1050, 8, 85, 10, 85, 12, 85, 1053, 9, 85, 1, 85, 1, 85, 4, 85, 1057, 8, 85, 11, 85, 12, 85, 1058, 3, 85, 1061, 8, 85, 1, 86, 1, 86, 1, 86, 1, 86, 1, 86, 1, 87, 1, 87, 1, 87, 1, 87, 1, 87, 1, 88, 1, 88, 5, 88, 1075, 8, 88, 10, 88, 12, 88, 1078, 9, 88, 1, 88, 1, 88, 3, 88, 1082, 8, 88, 1, 88, 4, 88, 1085, 8, 88, 11, 88, 12, 88, 1086, 3, 88, 1089, 8, 88, 1, 89, 1, 89, 4, 89, 1093, 8, 89, 11, 89, 12, 89, 1094, 1, 89, 1, 89, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 103, 1, 104, 1, 104, 1, 104, 1, 104, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 105, 1, 106, 1, 106, 1, 106, 3, 106, 1172, 8, 106, 1, 107, 4, 107, 1175, 8, 107, 11, 107, 12, 107, 1176, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 1, 109, 1, 109, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 116, 1, 116, 1, 117, 1, 117, 1, 117, 1, 117, 1, 118, 1, 118, 1, 118, 1, 118, 3, 118, 1224, 8, 118, 1, 119, 1, 119, 3, 119, 1228, 8, 119, 1, 119, 5, 119, 1231, 8, 119, 10, 119, 12, 119, 1234, 9, 119, 1, 119, 1, 119, 3, 119, 1238, 8, 119, 1, 119, 4, 119, 1241, 8, 119, 11, 119, 12, 119, 1242, 3, 119, 1245, 8, 119, 1, 120, 1, 120, 4, 120, 1249, 8, 120, 11, 120, 12, 120, 1250, 1, 121, 1, 121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 137, 1, 137, 1, 137, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 138, 1, 139, 1, 139, 1, 140, 4, 140, 1334, 8, 140, 11, 140, 12, 140, 1335, 1, 140, 1, 140, 3, 140, 1340, 8, 140, 1, 140, 4, 140, 1343, 8, 140, 11, 140, 12, 140, 1344, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 1, 143, 1, 143, 1, 143, 1, 144, 1, 144, 1, 144, 1, 144, 1, 145, 1, 145, 1, 145, 1, 145, 1, 145, 1, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 148, 1, 148, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, 152, 1, 152, 1, 152, 1, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 155, 1, 155, 1, 155, 1, 155, 1, 156, 1, 156, 1, 156, 1, 156, 1, 157, 1, 157, 1, 157, 1, 157, 1, 157, 1, 158, 1, 158, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 163, 1, 163, 1, 163, 1, 163, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1, 171, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, 1, 173, 1, 173, 1, 173, 1, 173, 4, 173, 1486, 8, 173, 11, 173, 12, 173, 1487, 1, 174, 1, 174, 1, 174, 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 177, 1, 177, 1, 177, 1, 178, 1, 178, 1, 178, 1, 178, 1, 179, 1, 179, 1, 179, 1, 179, 1, 180, 1, 180, 1, 180, 1, 180, 1, 181, 1, 181, 1, 181, 1, 181, 1, 181, 1, 182, 1, 182, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, 183, 1, 184, 1, 184, 1, 184, 1, 184, 1, 185, 1, 185, 1, 185, 1, 185, 1, 186, 1, 186, 1, 186, 1, 186, 1, 187, 1, 187, 1, 187, 1, 187, 1, 187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 189, 1, 189, 1, 189, 1, 189, 1, 190, 1, 190, 1, 190, 1, 190, 1, 191, 1, 191, 1, 191, 1, 191, 1, 192, 1, 192, 1, 192, 1, 192, 1, 193, 1, 193, 1, 193, 1, 193, 1, 194, 1, 194, 1, 194, 1, 194, 1, 194, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 196, 1, 196, 1, 196, 1, 196, 1, 197, 1, 197, 1, 197, 1, 197, 1, 197, 1, 197, 1, 198, 1, 198, 1, 198, 1, 198, 1, 198, 1, 198, 1, 198, 1, 198, 1, 198, 1, 199, 1, 199, 1, 199, 1, 199, 1, 200, 1, 200, 1, 200, 1, 200, 1, 201, 1, 201, 1, 201, 1, 201, 1, 202, 1, 202, 1, 202, 1, 202, 1, 203, 1, 203, 1, 203, 1, 203, 1, 204, 1, 204, 1, 204, 1, 204, 1, 205, 1, 205, 1, 205, 1, 205, 1, 206, 1, 206, 1, 206, 1, 206, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 208, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 209, 1, 210, 1, 210, 1, 210, 1, 210, 1, 211, 1, 211, 1, 211, 1, 211, 1, 212, 1, 212, 1, 212, 1, 212, 1, 213, 1, 213, 1, 213, 1, 213, 1, 213, 1, 213, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 214, 1, 215, 1, 215, 1, 215, 1, 215, 1, 216, 1, 216, 1, 216, 1, 216, 1, 217, 1, 217, 1, 217, 1, 217, 1, 218, 1, 218, 1, 218, 1, 218, 1, 218, 1, 218, 1, 219, 1, 219, 1, 219, 1, 219, 1, 219, 1, 219, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 221, 1, 221, 1, 221, 1, 221, 1, 221, 1, 222, 1, 222, 1, 222, 1, 222, 1, 222, 1, 223, 1, 223, 1, 223, 1, 223, 1, 224, 1, 224, 1, 224, 1, 224, 1, 225, 1, 225, 1, 225, 1, 225, 1, 226, 1, 226, 1, 226, 1, 226, 1, 227, 1, 227, 1, 227, 1, 227, 1, 228, 1, 228, 1, 228, 1, 228, 1, 229, 1, 229, 1, 229, 1, 229, 1, 230, 1, 230, 1, 230, 1, 230, 1, 231, 1, 231, 1, 231, 1, 231, 1, 232, 1, 232, 1, 232, 1, 232, 1, 232, 1, 233, 1, 233, 1, 233, 1, 233, 1, 234, 1, 234, 1, 234, 1, 234, 1, 235, 1, 235, 1, 235, 1, 235, 1, 236, 1, 236, 1, 236, 1, 236, 1, 237, 1, 237, 1, 237, 1, 237, 1, 237, 1, 238, 1, 238, 1, 238, 1, 238, 1, 238, 1, 239, 1, 239, 1, 239, 1, 239, 1, 239, 1, 240, 1, 240, 1, 240, 1, 240, 1, 241, 1, 241, 1, 241, 1, 241, 1, 242, 1, 242, 1, 242, 1, 242, 2, 773, 842, 0, 243, 19, 1, 21, 2, 23, 3, 25, 4, 27, 5, 29, 6, 31, 7, 33, 8, 35, 9, 37, 10, 39, 11, 41, 12, 43, 13, 45, 14, 47, 15, 49, 16, 51, 17, 53, 18, 55, 19, 57, 20, 59, 21, 61, 22, 63, 23, 65, 24, 67, 25, 69, 26, 71, 27, 73, 28, 75, 29, 77, 30, 79, 31, 81, 0, 83, 0, 85, 0, 87, 0, 89, 0, 91, 0, 93, 0, 95, 0, 97, 0, 99, 0, 101, 32, 103, 33, 105, 34, 107, 35, 109, 36, 111, 37, 113, 38, 115, 39, 117, 40, 119, 41, 121, 42, 123, 43, 125, 44, 127, 45, 129, 46, 131, 47, 133, 48, 135, 49, 137, 50, 139, 51, 141, 52, 143, 53, 145, 54, 147, 55, 149, 56, 151, 57, 153, 58, 155, 59, 157, 60, 159, 61, 161, 62, 163, 63, 165, 64, 167, 65, 169, 66, 171, 67, 173, 68, 175, 69, 177, 70, 179, 71, 181, 72, 183, 0, 185, 0, 187, 0, 189, 73, 191, 74, 193, 75, 195, 76, 197, 0, 199, 77, 201, 78, 203, 79, 205, 80, 207, 0, 209, 0, 211, 81, 213, 82, 215, 83, 217, 0, 219, 0, 221, 0, 223, 0, 225, 0, 227, 0, 229, 84, 231, 0, 233, 85, 235, 0, 237, 0, 239, 86, 241, 87, 243, 88, 245, 0, 247, 0, 249, 0, 251, 0, 253, 0, 255, 0, 257, 0, 259, 89, 261, 90, 263, 91, 265, 92, 267, 0, 269, 0, 271, 0, 273, 0, 275, 0, 277, 0, 279, 93, 281, 0, 283, 94, 285, 95, 287, 96, 289, 0, 291, 0, 293, 97, 295, 98, 297, 0, 299, 99, 301, 0, 303, 100, 305, 101, 307, 102, 309, 0, 311, 0, 313, 0, 315, 0, 317, 0, 319, 0, 321, 0, 323, 0, 325, 0, 327, 103, 329, 104, 331, 105, 333, 0, 335, 0, 337, 0, 339, 0, 341, 0, 343, 0, 345, 106, 347, 107, 349, 108, 351, 0, 353, 109, 355, 110, 357, 111, 359, 112, 361, 0, 363, 0, 365, 113, 367, 114, 369, 115, 371, 116, 373, 0, 375, 0, 377, 0, 379, 0, 381, 0, 383, 0, 385, 0, 387, 117, 389, 118, 391, 119, 393, 0, 395, 0, 397, 0, 399, 0, 401, 120, 403, 121, 405, 122, 407, 0, 409, 123, 411, 0, 413, 0, 415, 124, 417, 0, 419, 0, 421, 0, 423, 0, 425, 0, 427, 125, 429, 126, 431, 127, 433, 0, 435, 0, 437, 0, 439, 128, 441, 129, 443, 130, 445, 0, 447, 0, 449, 131, 451, 132, 453, 133, 455, 0, 457, 0, 459, 0, 461, 0, 463, 0, 465, 0, 467, 0, 469, 0, 471, 0, 473, 0, 475, 0, 477, 134, 479, 135, 481, 136, 483, 0, 485, 0, 487, 137, 489, 138, 491, 139, 493, 0, 495, 0, 497, 0, 499, 140, 501, 141, 503, 142, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 36, 2, 0, 68, 68, 100, 100, 2, 0, 73, 73, 105, 105, 2, 0, 83, 83, 115, 115, 2, 0, 69, 69, 101, 101, 2, 0, 67, 67, 99, 99, 2, 0, 84, 84, 116, 116, 2, 0, 82, 82, 114, 114, 2, 0, 79, 79, 111, 111, 2, 0, 80, 80, 112, 112, 2, 0, 78, 78, 110, 110, 2, 0, 72, 72, 104, 104, 2, 0, 86, 86, 118, 118, 2, 0, 65, 65, 97, 97, 2, 0, 76, 76, 108, 108, 2, 0, 88, 88, 120, 120, 2, 0, 70, 70, 102, 102, 2, 0, 77, 77, 109, 109, 2, 0, 71, 71, 103, 103, 2, 0, 75, 75, 107, 107, 2, 0, 87, 87, 119, 119, 2, 0, 85, 85, 117, 117, 6, 0, 9, 10, 13, 13, 32, 32, 47, 47, 91, 91, 93, 93, 2, 0, 10, 10, 13, 13, 3, 0, 9, 10, 13, 13, 32, 32, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 8, 0, 34, 34, 78, 78, 82, 82, 84, 84, 92, 92, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 2, 0, 43, 43, 45, 45, 1, 0, 96, 96, 2, 0, 66, 66, 98, 98, 2, 0, 89, 89, 121, 121, 11, 0, 9, 10, 13, 13, 32, 32, 34, 34, 44, 44, 47, 47, 58, 58, 61, 61, 91, 91, 93, 93, 124, 124, 2, 0, 42, 42, 47, 47, 11, 0, 9, 10, 13, 13, 32, 32, 34, 35, 44, 44, 47, 47, 58, 58, 60, 60, 62, 63, 92, 92, 124, 124, 2, 0, 74, 74, 106, 106, 1823, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 1, 79, 1, 0, 0, 0, 1, 101, 1, 0, 0, 0, 1, 103, 1, 0, 0, 0, 1, 105, 1, 0, 0, 0, 1, 107, 1, 0, 0, 0, 1, 109, 1, 0, 0, 0, 1, 111, 1, 0, 0, 0, 1, 113, 1, 0, 0, 0, 1, 115, 1, 0, 0, 0, 1, 117, 1, 0, 0, 0, 1, 119, 1, 0, 0, 0, 1, 121, 1, 0, 0, 0, 1, 123, 1, 0, 0, 0, 1, 125, 1, 0, 0, 0, 1, 127, 1, 0, 0, 0, 1, 129, 1, 0, 0, 0, 1, 131, 1, 0, 0, 0, 1, 133, 1, 0, 0, 0, 1, 135, 1, 0, 0, 0, 1, 137, 1, 0, 0, 0, 1, 139, 1, 0, 0, 0, 1, 141, 1, 0, 0, 0, 1, 143, 1, 0, 0, 0, 1, 145, 1, 0, 0, 0, 1, 147, 1, 0, 0, 0, 1, 149, 1, 0, 0, 0, 1, 151, 1, 0, 0, 0, 1, 153, 1, 0, 0, 0, 1, 155, 1, 0, 0, 0, 1, 157, 1, 0, 0, 0, 1, 159, 1, 0, 0, 0, 1, 161, 1, 0, 0, 0, 1, 163, 1, 0, 0, 0, 1, 165, 1, 0, 0, 0, 1, 167, 1, 0, 0, 0, 1, 169, 1, 0, 0, 0, 1, 171, 1, 0, 0, 0, 1, 173, 1, 0, 0, 0, 1, 175, 1, 0, 0, 0, 1, 177, 1, 0, 0, 0, 1, 179, 1, 0, 0, 0, 1, 181, 1, 0, 0, 0, 1, 183, 1, 0, 0, 0, 1, 185, 1, 0, 0, 0, 1, 187, 1, 0, 0, 0, 1, 189, 1, 0, 0, 0, 1, 191, 1, 0, 0, 0, 1, 193, 1, 0, 0, 0, 1, 195, 1, 0, 0, 0, 1, 199, 1, 0, 0, 0, 1, 201, 1, 0, 0, 0, 1, 203, 1, 0, 0, 0, 1, 205, 1, 0, 0, 0, 2, 207, 1, 0, 0, 0, 2, 209, 1, 0, 0, 0, 2, 211, 1, 0, 0, 0, 2, 213, 1, 0, 0, 0, 2, 215, 1, 0, 0, 0, 3, 217, 1, 0, 0, 0, 3, 219, 1, 0, 0, 0, 3, 221, 1, 0, 0, 0, 3, 223, 1, 0, 0, 0, 3, 225, 1, 0, 0, 0, 3, 227, 1, 0, 0, 0, 3, 229, 1, 0, 0, 0, 3, 233, 1, 0, 0, 0, 3, 235, 1, 0, 0, 0, 3, 237, 1, 0, 0, 0, 3, 239, 1, 0, 0, 0, 3, 241, 1, 0, 0, 0, 3, 243, 1, 0, 0, 0, 4, 245, 1, 0, 0, 0, 4, 247, 1, 0, 0, 0, 4, 249, 1, 0, 0, 0, 4, 251, 1, 0, 0, 0, 4, 253, 1, 0, 0, 0, 4, 259, 1, 0, 0, 0, 4, 261, 1, 0, 0, 0, 4, 263, 1, 0, 0, 0, 4, 265, 1, 0, 0, 0, 5, 267, 1, 0, 0, 0, 5, 269, 1, 0, 0, 0, 5, 271, 1, 0, 0, 0, 5, 273, 1, 0, 0, 0, 5, 275, 1, 0, 0, 0, 5, 277, 1, 0, 0, 0, 5, 279, 1, 0, 0, 0, 5, 281, 1, 0, 0, 0, 5, 283, 1, 0, 0, 0, 5, 285, 1, 0, 0, 0, 5, 287, 1, 0, 0, 0, 6, 289, 1, 0, 0, 0, 6, 291, 1, 0, 0, 0, 6, 293, 1, 0, 0, 0, 6, 295, 1, 0, 0, 0, 6, 299, 1, 0, 0, 0, 6, 301, 1, 0, 0, 0, 6, 303, 1, 0, 0, 0, 6, 305, 1, 0, 0, 0, 6, 307, 1, 0, 0, 0, 7, 309, 1, 0, 0, 0, 7, 311, 1, 0, 0, 0, 7, 313, 1, 0, 0, 0, 7, 315, 1, 0, 0, 0, 7, 317, 1, 0, 0, 0, 7, 319, 1, 0, 0, 0, 7, 321, 1, 0, 0, 0, 7, 323, 1, 0, 0, 0, 7, 325, 1, 0, 0, 0, 7, 327, 1, 0, 0, 0, 7, 329, 1, 0, 0, 0, 7, 331, 1, 0, 0, 0, 8, 333, 1, 0, 0, 0, 8, 335, 1, 0, 0, 0, 8, 337, 1, 0, 0, 0, 8, 339, 1, 0, 0, 0, 8, 341, 1, 0, 0, 0, 8, 343, 1, 0, 0, 0, 8, 345, 1, 0, 0, 0, 8, 347, 1, 0, 0, 0, 8, 349, 1, 0, 0, 0, 9, 351, 1, 0, 0, 0, 9, 353, 1, 0, 0, 0, 9, 355, 1, 0, 0, 0, 9, 357, 1, 0, 0, 0, 9, 359, 1, 0, 0, 0, 10, 361, 1, 0, 0, 0, 10, 363, 1, 0, 0, 0, 10, 365, 1, 0, 0, 0, 10, 367, 1, 0, 0, 0, 10, 369, 1, 0, 0, 0, 10, 371, 1, 0, 0, 0, 11, 373, 1, 0, 0, 0, 11, 375, 1, 0, 0, 0, 11, 377, 1, 0, 0, 0, 11, 379, 1, 0, 0, 0, 11, 381, 1, 0, 0, 0, 11, 383, 1, 0, 0, 0, 11, 385, 1, 0, 0, 0, 11, 387, 1, 0, 0, 0, 11, 389, 1, 0, 0, 0, 11, 391, 1, 0, 0, 0, 12, 393, 1, 0, 0, 0, 12, 395, 1, 0, 0, 0, 12, 397, 1, 0, 0, 0, 12, 399, 1, 0, 0, 0, 12, 401, 1, 0, 0, 0, 12, 403, 1, 0, 0, 0, 12, 405, 1, 0, 0, 0, 13, 407, 1, 0, 0, 0, 13, 409, 1, 0, 0, 0, 13, 411, 1, 0, 0, 0, 13, 413, 1, 0, 0, 0, 13, 415, 1, 0, 0, 0, 13, 417, 1, 0, 0, 0, 13, 419, 1, 0, 0, 0, 13, 421, 1, 0, 0, 0, 13, 423, 1, 0, 0, 0, 13, 425, 1, 0, 0, 0, 13, 427, 1, 0, 0, 0, 13, 429, 1, 0, 0, 0, 13, 431, 1, 0, 0, 0, 14, 433, 1, 0, 0, 0, 14, 435, 1, 0, 0, 0, 14, 437, 1, 0, 0, 0, 14, 439, 1, 0, 0, 0, 14, 441, 1, 0, 0, 0, 14, 443, 1, 0, 0, 0, 15, 445, 1, 0, 0, 0, 15, 447, 1, 0, 0, 0, 15, 449, 1, 0, 0, 0, 15, 451, 1, 0, 0, 0, 15, 453, 1, 0, 0, 0, 15, 455, 1, 0, 0, 0, 15, 457, 1, 0, 0, 0, 15, 459, 1, 0, 0, 0, 15, 461, 1, 0, 0, 0, 16, 463, 1, 0, 0, 0, 16, 465, 1, 0, 0, 0, 16, 467, 1, 0, 0, 0, 16, 469, 1, 0, 0, 0, 16, 471, 1, 0, 0, 0, 16, 473, 1, 0, 0, 0, 16, 475, 1, 0, 0, 0, 16, 477, 1, 0, 0, 0, 16, 479, 1, 0, 0, 0, 16, 481, 1, 0, 0, 0, 17, 483, 1, 0, 0, 0, 17, 485, 1, 0, 0, 0, 17, 487, 1, 0, 0, 0, 17, 489, 1, 0, 0, 0, 17, 491, 1, 0, 0, 0, 18, 493, 1, 0, 0, 0, 18, 495, 1, 0, 0, 0, 18, 497, 1, 0, 0, 0, 18, 499, 1, 0, 0, 0, 18, 501, 1, 0, 0, 0, 18, 503, 1, 0, 0, 0, 19, 505, 1, 0, 0, 0, 21, 515, 1, 0, 0, 0, 23, 522, 1, 0, 0, 0, 25, 531, 1, 0, 0, 0, 27, 538, 1, 0, 0, 0, 29, 548, 1, 0, 0, 0, 31, 555, 1, 0, 0, 0, 33, 562, 1, 0, 0, 0, 35, 569, 1, 0, 0, 0, 37, 577, 1, 0, 0, 0, 39, 589, 1, 0, 0, 0, 41, 598, 1, 0, 0, 0, 43, 604, 1, 0, 0, 0, 45, 611, 1, 0, 0, 0, 47, 618, 1, 0, 0, 0, 49, 626, 1, 0, 0, 0, 51, 634, 1, 0, 0, 0, 53, 643, 1, 0, 0, 0, 55, 659, 1, 0, 0, 0, 57, 674, 1, 0, 0, 0, 59, 686, 1, 0, 0, 0, 61, 698, 1, 0, 0, 0, 63, 709, 1, 0, 0, 0, 65, 717, 1, 0, 0, 0, 67, 725, 1, 0, 0, 0, 69, 734, 1, 0, 0, 0, 71, 743, 1, 0, 0, 0, 73, 749, 1, 0, 0, 0, 75, 766, 1, 0, 0, 0, 77, 782, 1, 0, 0, 0, 79, 788, 1, 0, 0, 0, 81, 792, 1, 0, 0, 0, 83, 794, 1, 0, 0, 0, 85, 796, 1, 0, 0, 0, 87, 799, 1, 0, 0, 0, 89, 801, 1, 0, 0, 0, 91, 810, 1, 0, 0, 0, 93, 812, 1, 0, 0, 0, 95, 817, 1, 0, 0, 0, 97, 819, 1, 0, 0, 0, 99, 824, 1, 0, 0, 0, 101, 855, 1, 0, 0, 0, 103, 858, 1, 0, 0, 0, 105, 904, 1, 0, 0, 0, 107, 906, 1, 0, 0, 0, 109, 909, 1, 0, 0, 0, 111, 913, 1, 0, 0, 0, 113, 917, 1, 0, 0, 0, 115, 919, 1, 0, 0, 0, 117, 922, 1, 0, 0, 0, 119, 924, 1, 0, 0, 0, 121, 926, 1, 0, 0, 0, 123, 931, 1, 0, 0, 0, 125, 933, 1, 0, 0, 0, 127, 939, 1, 0, 0, 0, 129, 945, 1, 0, 0, 0, 131, 948, 1, 0, 0, 0, 133, 951, 1, 0, 0, 0, 135, 956, 1, 0, 0, 0, 137, 961, 1, 0, 0, 0, 139, 963, 1, 0, 0, 0, 141, 967, 1, 0, 0, 0, 143, 972, 1, 0, 0, 0, 145, 978, 1, 0, 0, 0, 147, 981, 1, 0, 0, 0, 149, 983, 1, 0, 0, 0, 151, 989, 1, 0, 0, 0, 153, 991, 1, 0, 0, 0, 155, 996, 1, 0, 0, 0, 157, 999, 1, 0, 0, 0, 159, 1002, 1, 0, 0, 0, 161, 1005, 1, 0, 0, 0, 163, 1007, 1, 0, 0, 0, 165, 1010, 1, 0, 0, 0, 167, 1012, 1, 0, 0, 0, 169, 1015, 1, 0, 0, 0, 171, 1017, 1, 0, 0, 0, 173, 1019, 1, 0, 0, 0, 175, 1021, 1, 0, 0, 0, 177, 1023, 1, 0, 0, 0, 179, 1025, 1, 0, 0, 0, 181, 1027, 1, 0, 0, 0, 183, 1029, 1, 0, 0, 0, 185, 1033, 1, 0, 0, 0, 187, 1038, 1, 0, 0, 0, 189, 1060, 1, 0, 0, 0, 191, 1062, 1, 0, 0, 0, 193, 1067, 1, 0, 0, 0, 195, 1088, 1, 0, 0, 0, 197, 1090, 1, 0, 0, 0, 199, 1098, 1, 0, 0, 0, 201, 1100, 1, 0, 0, 0, 203, 1104, 1, 0, 0, 0, 205, 1108, 1, 0, 0, 0, 207, 1112, 1, 0, 0, 0, 209, 1117, 1, 0, 0, 0, 211, 1122, 1, 0, 0, 0, 213, 1126, 1, 0, 0, 0, 215, 1130, 1, 0, 0, 0, 217, 1134, 1, 0, 0, 0, 219, 1139, 1, 0, 0, 0, 221, 1143, 1, 0, 0, 0, 223, 1147, 1, 0, 0, 0, 225, 1151, 1, 0, 0, 0, 227, 1155, 1, 0, 0, 0, 229, 1159, 1, 0, 0, 0, 231, 1171, 1, 0, 0, 0, 233, 1174, 1, 0, 0, 0, 235, 1178, 1, 0, 0, 0, 237, 1182, 1, 0, 0, 0, 239, 1186, 1, 0, 0, 0, 241, 1190, 1, 0, 0, 0, 243, 1194, 1, 0, 0, 0, 245, 1198, 1, 0, 0, 0, 247, 1203, 1, 0, 0, 0, 249, 1207, 1, 0, 0, 0, 251, 1211, 1, 0, 0, 0, 253, 1215, 1, 0, 0, 0, 255, 1223, 1, 0, 0, 0, 257, 1244, 1, 0, 0, 0, 259, 1248, 1, 0, 0, 0, 261, 1252, 1, 0, 0, 0, 263, 1256, 1, 0, 0, 0, 265, 1260, 1, 0, 0, 0, 267, 1264, 1, 0, 0, 0, 269, 1269, 1, 0, 0, 0, 271, 1273, 1, 0, 0, 0, 273, 1277, 1, 0, 0, 0, 275, 1281, 1, 0, 0, 0, 277, 1285, 1, 0, 0, 0, 279, 1289, 1, 0, 0, 0, 281, 1292, 1, 0, 0, 0, 283, 1296, 1, 0, 0, 0, 285, 1300, 1, 0, 0, 0, 287, 1304, 1, 0, 0, 0, 289, 1308, 1, 0, 0, 0, 291, 1313, 1, 0, 0, 0, 293, 1318, 1, 0, 0, 0, 295, 1323, 1, 0, 0, 0, 297, 1330, 1, 0, 0, 0, 299, 1339, 1, 0, 0, 0, 301, 1346, 1, 0, 0, 0, 303, 1350, 1, 0, 0, 0, 305, 1354, 1, 0, 0, 0, 307, 1358, 1, 0, 0, 0, 309, 1362, 1, 0, 0, 0, 311, 1368, 1, 0, 0, 0, 313, 1372, 1, 0, 0, 0, 315, 1376, 1, 0, 0, 0, 317, 1380, 1, 0, 0, 0, 319, 1384, 1, 0, 0, 0, 321, 1388, 1, 0, 0, 0, 323, 1392, 1, 0, 0, 0, 325, 1396, 1, 0, 0, 0, 327, 1400, 1, 0, 0, 0, 329, 1404, 1, 0, 0, 0, 331, 1408, 1, 0, 0, 0, 333, 1412, 1, 0, 0, 0, 335, 1417, 1, 0, 0, 0, 337, 1421, 1, 0, 0, 0, 339, 1425, 1, 0, 0, 0, 341, 1429, 1, 0, 0, 0, 343, 1433, 1, 0, 0, 0, 345, 1437, 1, 0, 0, 0, 347, 1441, 1, 0, 0, 0, 349, 1445, 1, 0, 0, 0, 351, 1449, 1, 0, 0, 0, 353, 1454, 1, 0, 0, 0, 355, 1459, 1, 0, 0, 0, 357, 1463, 1, 0, 0, 0, 359, 1467, 1, 0, 0, 0, 361, 1471, 1, 0, 0, 0, 363, 1476, 1, 0, 0, 0, 365, 1485, 1, 0, 0, 0, 367, 1489, 1, 0, 0, 0, 369, 1493, 1, 0, 0, 0, 371, 1497, 1, 0, 0, 0, 373, 1501, 1, 0, 0, 0, 375, 1506, 1, 0, 0, 0, 377, 1510, 1, 0, 0, 0, 379, 1514, 1, 0, 0, 0, 381, 1518, 1, 0, 0, 0, 383, 1523, 1, 0, 0, 0, 385, 1527, 1, 0, 0, 0, 387, 1531, 1, 0, 0, 0, 389, 1535, 1, 0, 0, 0, 391, 1539, 1, 0, 0, 0, 393, 1543, 1, 0, 0, 0, 395, 1549, 1, 0, 0, 0, 397, 1553, 1, 0, 0, 0, 399, 1557, 1, 0, 0, 0, 401, 1561, 1, 0, 0, 0, 403, 1565, 1, 0, 0, 0, 405, 1569, 1, 0, 0, 0, 407, 1573, 1, 0, 0, 0, 409, 1578, 1, 0, 0, 0, 411, 1583, 1, 0, 0, 0, 413, 1587, 1, 0, 0, 0, 415, 1593, 1, 0, 0, 0, 417, 1602, 1, 0, 0, 0, 419, 1606, 1, 0, 0, 0, 421, 1610, 1, 0, 0, 0, 423, 1614, 1, 0, 0, 0, 425, 1618, 1, 0, 0, 0, 427, 1622, 1, 0, 0, 0, 429, 1626, 1, 0, 0, 0, 431, 1630, 1, 0, 0, 0, 433, 1634, 1, 0, 0, 0, 435, 1639, 1, 0, 0, 0, 437, 1645, 1, 0, 0, 0, 439, 1651, 1, 0, 0, 0, 441, 1655, 1, 0, 0, 0, 443, 1659, 1, 0, 0, 0, 445, 1663, 1, 0, 0, 0, 447, 1669, 1, 0, 0, 0, 449, 1675, 1, 0, 0, 0, 451, 1679, 1, 0, 0, 0, 453, 1683, 1, 0, 0, 0, 455, 1687, 1, 0, 0, 0, 457, 1693, 1, 0, 0, 0, 459, 1699, 1, 0, 0, 0, 461, 1705, 1, 0, 0, 0, 463, 1710, 1, 0, 0, 0, 465, 1715, 1, 0, 0, 0, 467, 1719, 1, 0, 0, 0, 469, 1723, 1, 0, 0, 0, 471, 1727, 1, 0, 0, 0, 473, 1731, 1, 0, 0, 0, 475, 1735, 1, 0, 0, 0, 477, 1739, 1, 0, 0, 0, 479, 1743, 1, 0, 0, 0, 481, 1747, 1, 0, 0, 0, 483, 1751, 1, 0, 0, 0, 485, 1756, 1, 0, 0, 0, 487, 1760, 1, 0, 0, 0, 489, 1764, 1, 0, 0, 0, 491, 1768, 1, 0, 0, 0, 493, 1772, 1, 0, 0, 0, 495, 1777, 1, 0, 0, 0, 497, 1782, 1, 0, 0, 0, 499, 1787, 1, 0, 0, 0, 501, 1791, 1, 0, 0, 0, 503, 1795, 1, 0, 0, 0, 505, 506, 7, 0, 0, 0, 506, 507, 7, 1, 0, 0, 507, 508, 7, 2, 0, 0, 508, 509, 7, 2, 0, 0, 509, 510, 7, 3, 0, 0, 510, 511, 7, 4, 0, 0, 511, 512, 7, 5, 0, 0, 512, 513, 1, 0, 0, 0, 513, 514, 6, 0, 0, 0, 514, 20, 1, 0, 0, 0, 515, 516, 7, 0, 0, 0, 516, 517, 7, 6, 0, 0, 517, 518, 7, 7, 0, 0, 518, 519, 7, 8, 0, 0, 519, 520, 1, 0, 0, 0, 520, 521, 6, 1, 1, 0, 521, 22, 1, 0, 0, 0, 522, 523, 7, 3, 0, 0, 523, 524, 7, 9, 0, 0, 524, 525, 7, 6, 0, 0, 525, 526, 7, 1, 0, 0, 526, 527, 7, 4, 0, 0, 527, 528, 7, 10, 0, 0, 528, 529, 1, 0, 0, 0, 529, 530, 6, 2, 2, 0, 530, 24, 1, 0, 0, 0, 531, 532, 7, 3, 0, 0, 532, 533, 7, 11, 0, 0, 533, 534, 7, 12, 0, 0, 534, 535, 7, 13, 0, 0, 535, 536, 1, 0, 0, 0, 536, 537, 6, 3, 0, 0, 537, 26, 1, 0, 0, 0, 538, 539, 7, 3, 0, 0, 539, 540, 7, 14, 0, 0, 540, 541, 7, 8, 0, 0, 541, 542, 7, 13, 0, 0, 542, 543, 7, 12, 0, 0, 543, 544, 7, 1, 0, 0, 544, 545, 7, 9, 0, 0, 545, 546, 1, 0, 0, 0, 546, 547, 6, 4, 3, 0, 547, 28, 1, 0, 0, 0, 548, 549, 7, 15, 0, 0, 549, 550, 7, 6, 0, 0, 550, 551, 7, 7, 0, 0, 551, 552, 7, 16, 0, 0, 552, 553, 1, 0, 0, 0, 553, 554, 6, 5, 4, 0, 554, 30, 1, 0, 0, 0, 555, 556, 7, 17, 0, 0, 556, 557, 7, 6, 0, 0, 557, 558, 7, 7, 0, 0, 558, 559, 7, 18, 0, 0, 559, 560, 1, 0, 0, 0, 560, 561, 6, 6, 0, 0, 561, 32, 1, 0, 0, 0, 562, 563, 7, 18, 0, 0, 563, 564, 7, 3, 0, 0, 564, 565, 7, 3, 0, 0, 565, 566, 7, 8, 0, 0, 566, 567, 1, 0, 0, 0, 567, 568, 6, 7, 1, 0, 568, 34, 1, 0, 0, 0, 569, 570, 7, 13, 0, 0, 570, 571, 7, 1, 0, 0, 571, 572, 7, 16, 0, 0, 572, 573, 7, 1, 0, 0, 573, 574, 7, 5, 0, 0, 574, 575, 1, 0, 0, 0, 575, 576, 6, 8, 0, 0, 576, 36, 1, 0, 0, 0, 577, 578, 7, 16, 0, 0, 578, 579, 7, 11, 0, 0, 579, 580, 5, 95, 0, 0, 580, 581, 7, 3, 0, 0, 581, 582, 7, 14, 0, 0, 582, 583, 7, 8, 0, 0, 583, 584, 7, 12, 0, 0, 584, 585, 7, 9, 0, 0, 585, 586, 7, 0, 0, 0, 586, 587, 1, 0, 0, 0, 587, 588, 6, 9, 5, 0, 588, 38, 1, 0, 0, 0, 589, 590, 7, 6, 0, 0, 590, 591, 7, 3, 0, 0, 591, 592, 7, 9, 0, 0, 592, 593, 7, 12, 0, 0, 593, 594, 7, 16, 0, 0, 594, 595, 7, 3, 0, 0, 595, 596, 1, 0, 0, 0, 596, 597, 6, 10, 6, 0, 597, 40, 1, 0, 0, 0, 598, 599, 7, 6, 0, 0, 599, 600, 7, 7, 0, 0, 600, 601, 7, 19, 0, 0, 601, 602, 1, 0, 0, 0, 602, 603, 6, 11, 0, 0, 603, 42, 1, 0, 0, 0, 604, 605, 7, 2, 0, 0, 605, 606, 7, 10, 0, 0, 606, 607, 7, 7, 0, 0, 607, 608, 7, 19, 0, 0, 608, 609, 1, 0, 0, 0, 609, 610, 6, 12, 7, 0, 610, 44, 1, 0, 0, 0, 611, 612, 7, 2, 0, 0, 612, 613, 7, 7, 0, 0, 613, 614, 7, 6, 0, 0, 614, 615, 7, 5, 0, 0, 615, 616, 1, 0, 0, 0, 616, 617, 6, 13, 0, 0, 617, 46, 1, 0, 0, 0, 618, 619, 7, 2, 0, 0, 619, 620, 7, 5, 0, 0, 620, 621, 7, 12, 0, 0, 621, 622, 7, 5, 0, 0, 622, 623, 7, 2, 0, 0, 623, 624, 1, 0, 0, 0, 624, 625, 6, 14, 0, 0, 625, 48, 1, 0, 0, 0, 626, 627, 7, 19, 0, 0, 627, 628, 7, 10, 0, 0, 628, 629, 7, 3, 0, 0, 629, 630, 7, 6, 0, 0, 630, 631, 7, 3, 0, 0, 631, 632, 1, 0, 0, 0, 632, 633, 6, 15, 0, 0, 633, 50, 1, 0, 0, 0, 634, 635, 7, 13, 0, 0, 635, 636, 7, 7, 0, 0, 636, 637, 7, 7, 0, 0, 637, 638, 7, 18, 0, 0, 638, 639, 7, 20, 0, 0, 639, 640, 7, 8, 0, 0, 640, 641, 1, 0, 0, 0, 641, 642, 6, 16, 8, 0, 642, 52, 1, 0, 0, 0, 643, 644, 4, 17, 0, 0, 644, 645, 7, 4, 0, 0, 645, 646, 7, 10, 0, 0, 646, 647, 7, 12, 0, 0, 647, 648, 7, 9, 0, 0, 648, 649, 7, 17, 0, 0, 649, 650, 7, 3, 0, 0, 650, 651, 5, 95, 0, 0, 651, 652, 7, 8, 0, 0, 652, 653, 7, 7, 0, 0, 653, 654, 7, 1, 0, 0, 654, 655, 7, 9, 0, 0, 655, 656, 7, 5, 0, 0, 656, 657, 1, 0, 0, 0, 657, 658, 6, 17, 9, 0, 658, 54, 1, 0, 0, 0, 659, 660, 4, 18, 1, 0, 660, 661, 7, 1, 0, 0, 661, 662, 7, 9, 0, 0, 662, 663, 7, 13, 0, 0, 663, 664, 7, 1, 0, 0, 664, 665, 7, 9, 0, 0, 665, 666, 7, 3, 0, 0, 666, 667, 7, 2, 0, 0, 667, 668, 7, 5, 0, 0, 668, 669, 7, 12, 0, 0, 669, 670, 7, 5, 0, 0, 670, 671, 7, 2, 0, 0, 671, 672, 1, 0, 0, 0, 672, 673, 6, 18, 0, 0, 673, 56, 1, 0, 0, 0, 674, 675, 4, 19, 2, 0, 675, 676, 7, 1, 0, 0, 676, 677, 7, 9, 0, 0, 677, 678, 7, 2, 0, 0, 678, 679, 7, 1, 0, 0, 679, 680, 7, 2, 0, 0, 680, 681, 7, 5, 0, 0, 681, 682, 5, 95, 0, 0, 682, 683, 5, 128020, 0, 0, 683, 684, 1, 0, 0, 0, 684, 685, 6, 19, 1, 0, 685, 58, 1, 0, 0, 0, 686, 687, 4, 20, 3, 0, 687, 688, 7, 13, 0, 0, 688, 689, 7, 7, 0, 0, 689, 690, 7, 7, 0, 0, 690, 691, 7, 18, 0, 0, 691, 692, 7, 20, 0, 0, 692, 693, 7, 8, 0, 0, 693, 694, 5, 95, 0, 0, 694, 695, 5, 128020, 0, 0, 695, 696, 1, 0, 0, 0, 696, 697, 6, 20, 10, 0, 697, 60, 1, 0, 0, 0, 698, 699, 4, 21, 4, 0, 699, 700, 7, 16, 0, 0, 700, 701, 7, 3, 0, 0, 701, 702, 7, 5, 0, 0, 702, 703, 7, 6, 0, 0, 703, 704, 7, 1, 0, 0, 704, 705, 7, 4, 0, 0, 705, 706, 7, 2, 0, 0, 706, 707, 1, 0, 0, 0, 707, 708, 6, 21, 11, 0, 708, 62, 1, 0, 0, 0, 709, 710, 4, 22, 5, 0, 710, 711, 7, 15, 0, 0, 711, 712, 7, 20, 0, 0, 712, 713, 7, 13, 0, 0, 713, 714, 7, 13, 0, 0, 714, 715, 1, 0, 0, 0, 715, 716, 6, 22, 8, 0, 716, 64, 1, 0, 0, 0, 717, 718, 4, 23, 6, 0, 718, 719, 7, 13, 0, 0, 719, 720, 7, 3, 0, 0, 720, 721, 7, 15, 0, 0, 721, 722, 7, 5, 0, 0, 722, 723, 1, 0, 0, 0, 723, 724, 6, 23, 8, 0, 724, 66, 1, 0, 0, 0, 725, 726, 4, 24, 7, 0, 726, 727, 7, 6, 0, 0, 727, 728, 7, 1, 0, 0, 728, 729, 7, 17, 0, 0, 729, 730, 7, 10, 0, 0, 730, 731, 7, 5, 0, 0, 731, 732, 1, 0, 0, 0, 732, 733, 6, 24, 8, 0, 733, 68, 1, 0, 0, 0, 734, 735, 4, 25, 8, 0, 735, 736, 7, 15, 0, 0, 736, 737, 7, 7, 0, 0, 737, 738, 7, 6, 0, 0, 738, 739, 7, 18, 0, 0, 739, 740, 1, 0, 0, 0, 740, 741, 6, 25, 12, 0, 741, 70, 1, 0, 0, 0, 742, 744, 8, 21, 0, 0, 743, 742, 1, 0, 0, 0, 744, 745, 1, 0, 0, 0, 745, 743, 1, 0, 0, 0, 745, 746, 1, 0, 0, 0, 746, 747, 1, 0, 0, 0, 747, 748, 6, 26, 0, 0, 748, 72, 1, 0, 0, 0, 749, 750, 5, 47, 0, 0, 750, 751, 5, 47, 0, 0, 751, 755, 1, 0, 0, 0, 752, 754, 8, 22, 0, 0, 753, 752, 1, 0, 0, 0, 754, 757, 1, 0, 0, 0, 755, 753, 1, 0, 0, 0, 755, 756, 1, 0, 0, 0, 756, 759, 1, 0, 0, 0, 757, 755, 1, 0, 0, 0, 758, 760, 5, 13, 0, 0, 759, 758, 1, 0, 0, 0, 759, 760, 1, 0, 0, 0, 760, 762, 1, 0, 0, 0, 761, 763, 5, 10, 0, 0, 762, 761, 1, 0, 0, 0, 762, 763, 1, 0, 0, 0, 763, 764, 1, 0, 0, 0, 764, 765, 6, 27, 13, 0, 765, 74, 1, 0, 0, 0, 766, 767, 5, 47, 0, 0, 767, 768, 5, 42, 0, 0, 768, 773, 1, 0, 0, 0, 769, 772, 3, 75, 28, 0, 770, 772, 9, 0, 0, 0, 771, 769, 1, 0, 0, 0, 771, 770, 1, 0, 0, 0, 772, 775, 1, 0, 0, 0, 773, 774, 1, 0, 0, 0, 773, 771, 1, 0, 0, 0, 774, 776, 1, 0, 0, 0, 775, 773, 1, 0, 0, 0, 776, 777, 5, 42, 0, 0, 777, 778, 5, 47, 0, 0, 778, 779, 1, 0, 0, 0, 779, 780, 6, 28, 13, 0, 780, 76, 1, 0, 0, 0, 781, 783, 7, 23, 0, 0, 782, 781, 1, 0, 0, 0, 783, 784, 1, 0, 0, 0, 784, 782, 1, 0, 0, 0, 784, 785, 1, 0, 0, 0, 785, 786, 1, 0, 0, 0, 786, 787, 6, 29, 13, 0, 787, 78, 1, 0, 0, 0, 788, 789, 5, 124, 0, 0, 789, 790, 1, 0, 0, 0, 790, 791, 6, 30, 14, 0, 791, 80, 1, 0, 0, 0, 792, 793, 7, 24, 0, 0, 793, 82, 1, 0, 0, 0, 794, 795, 7, 25, 0, 0, 795, 84, 1, 0, 0, 0, 796, 797, 5, 92, 0, 0, 797, 798, 7, 26, 0, 0, 798, 86, 1, 0, 0, 0, 799, 800, 8, 27, 0, 0, 800, 88, 1, 0, 0, 0, 801, 803, 7, 3, 0, 0, 802, 804, 7, 28, 0, 0, 803, 802, 1, 0, 0, 0, 803, 804, 1, 0, 0, 0, 804, 806, 1, 0, 0, 0, 805, 807, 3, 81, 31, 0, 806, 805, 1, 0, 0, 0, 807, 808, 1, 0, 0, 0, 808, 806, 1, 0, 0, 0, 808, 809, 1, 0, 0, 0, 809, 90, 1, 0, 0, 0, 810, 811, 5, 64, 0, 0, 811, 92, 1, 0, 0, 0, 812, 813, 5, 96, 0, 0, 813, 94, 1, 0, 0, 0, 814, 818, 8, 29, 0, 0, 815, 816, 5, 96, 0, 0, 816, 818, 5, 96, 0, 0, 817, 814, 1, 0, 0, 0, 817, 815, 1, 0, 0, 0, 818, 96, 1, 0, 0, 0, 819, 820, 5, 95, 0, 0, 820, 98, 1, 0, 0, 0, 821, 825, 3, 83, 32, 0, 822, 825, 3, 81, 31, 0, 823, 825, 3, 97, 39, 0, 824, 821, 1, 0, 0, 0, 824, 822, 1, 0, 0, 0, 824, 823, 1, 0, 0, 0, 825, 100, 1, 0, 0, 0, 826, 831, 5, 34, 0, 0, 827, 830, 3, 85, 33, 0, 828, 830, 3, 87, 34, 0, 829, 827, 1, 0, 0, 0, 829, 828, 1, 0, 0, 0, 830, 833, 1, 0, 0, 0, 831, 829, 1, 0, 0, 0, 831, 832, 1, 0, 0, 0, 832, 834, 1, 0, 0, 0, 833, 831, 1, 0, 0, 0, 834, 856, 5, 34, 0, 0, 835, 836, 5, 34, 0, 0, 836, 837, 5, 34, 0, 0, 837, 838, 5, 34, 0, 0, 838, 842, 1, 0, 0, 0, 839, 841, 8, 22, 0, 0, 840, 839, 1, 0, 0, 0, 841, 844, 1, 0, 0, 0, 842, 843, 1, 0, 0, 0, 842, 840, 1, 0, 0, 0, 843, 845, 1, 0, 0, 0, 844, 842, 1, 0, 0, 0, 845, 846, 5, 34, 0, 0, 846, 847, 5, 34, 0, 0, 847, 848, 5, 34, 0, 0, 848, 850, 1, 0, 0, 0, 849, 851, 5, 34, 0, 0, 850, 849, 1, 0, 0, 0, 850, 851, 1, 0, 0, 0, 851, 853, 1, 0, 0, 0, 852, 854, 5, 34, 0, 0, 853, 852, 1, 0, 0, 0, 853, 854, 1, 0, 0, 0, 854, 856, 1, 0, 0, 0, 855, 826, 1, 0, 0, 0, 855, 835, 1, 0, 0, 0, 856, 102, 1, 0, 0, 0, 857, 859, 3, 81, 31, 0, 858, 857, 1, 0, 0, 0, 859, 860, 1, 0, 0, 0, 860, 858, 1, 0, 0, 0, 860, 861, 1, 0, 0, 0, 861, 104, 1, 0, 0, 0, 862, 864, 3, 81, 31, 0, 863, 862, 1, 0, 0, 0, 864, 865, 1, 0, 0, 0, 865, 863, 1, 0, 0, 0, 865, 866, 1, 0, 0, 0, 866, 867, 1, 0, 0, 0, 867, 871, 3, 123, 52, 0, 868, 870, 3, 81, 31, 0, 869, 868, 1, 0, 0, 0, 870, 873, 1, 0, 0, 0, 871, 869, 1, 0, 0, 0, 871, 872, 1, 0, 0, 0, 872, 905, 1, 0, 0, 0, 873, 871, 1, 0, 0, 0, 874, 876, 3, 123, 52, 0, 875, 877, 3, 81, 31, 0, 876, 875, 1, 0, 0, 0, 877, 878, 1, 0, 0, 0, 878, 876, 1, 0, 0, 0, 878, 879, 1, 0, 0, 0, 879, 905, 1, 0, 0, 0, 880, 882, 3, 81, 31, 0, 881, 880, 1, 0, 0, 0, 882, 883, 1, 0, 0, 0, 883, 881, 1, 0, 0, 0, 883, 884, 1, 0, 0, 0, 884, 892, 1, 0, 0, 0, 885, 889, 3, 123, 52, 0, 886, 888, 3, 81, 31, 0, 887, 886, 1, 0, 0, 0, 888, 891, 1, 0, 0, 0, 889, 887, 1, 0, 0, 0, 889, 890, 1, 0, 0, 0, 890, 893, 1, 0, 0, 0, 891, 889, 1, 0, 0, 0, 892, 885, 1, 0, 0, 0, 892, 893, 1, 0, 0, 0, 893, 894, 1, 0, 0, 0, 894, 895, 3, 89, 35, 0, 895, 905, 1, 0, 0, 0, 896, 898, 3, 123, 52, 0, 897, 899, 3, 81, 31, 0, 898, 897, 1, 0, 0, 0, 899, 900, 1, 0, 0, 0, 900, 898, 1, 0, 0, 0, 900, 901, 1, 0, 0, 0, 901, 902, 1, 0, 0, 0, 902, 903, 3, 89, 35, 0, 903, 905, 1, 0, 0, 0, 904, 863, 1, 0, 0, 0, 904, 874, 1, 0, 0, 0, 904, 881, 1, 0, 0, 0, 904, 896, 1, 0, 0, 0, 905, 106, 1, 0, 0, 0, 906, 907, 7, 30, 0, 0, 907, 908, 7, 31, 0, 0, 908, 108, 1, 0, 0, 0, 909, 910, 7, 12, 0, 0, 910, 911, 7, 9, 0, 0, 911, 912, 7, 0, 0, 0, 912, 110, 1, 0, 0, 0, 913, 914, 7, 12, 0, 0, 914, 915, 7, 2, 0, 0, 915, 916, 7, 4, 0, 0, 916, 112, 1, 0, 0, 0, 917, 918, 5, 61, 0, 0, 918, 114, 1, 0, 0, 0, 919, 920, 5, 58, 0, 0, 920, 921, 5, 58, 0, 0, 921, 116, 1, 0, 0, 0, 922, 923, 5, 58, 0, 0, 923, 118, 1, 0, 0, 0, 924, 925, 5, 44, 0, 0, 925, 120, 1, 0, 0, 0, 926, 927, 7, 0, 0, 0, 927, 928, 7, 3, 0, 0, 928, 929, 7, 2, 0, 0, 929, 930, 7, 4, 0, 0, 930, 122, 1, 0, 0, 0, 931, 932, 5, 46, 0, 0, 932, 124, 1, 0, 0, 0, 933, 934, 7, 15, 0, 0, 934, 935, 7, 12, 0, 0, 935, 936, 7, 13, 0, 0, 936, 937, 7, 2, 0, 0, 937, 938, 7, 3, 0, 0, 938, 126, 1, 0, 0, 0, 939, 940, 7, 15, 0, 0, 940, 941, 7, 1, 0, 0, 941, 942, 7, 6, 0, 0, 942, 943, 7, 2, 0, 0, 943, 944, 7, 5, 0, 0, 944, 128, 1, 0, 0, 0, 945, 946, 7, 1, 0, 0, 946, 947, 7, 9, 0, 0, 947, 130, 1, 0, 0, 0, 948, 949, 7, 1, 0, 0, 949, 950, 7, 2, 0, 0, 950, 132, 1, 0, 0, 0, 951, 952, 7, 13, 0, 0, 952, 953, 7, 12, 0, 0, 953, 954, 7, 2, 0, 0, 954, 955, 7, 5, 0, 0, 955, 134, 1, 0, 0, 0, 956, 957, 7, 13, 0, 0, 957, 958, 7, 1, 0, 0, 958, 959, 7, 18, 0, 0, 959, 960, 7, 3, 0, 0, 960, 136, 1, 0, 0, 0, 961, 962, 5, 40, 0, 0, 962, 138, 1, 0, 0, 0, 963, 964, 7, 9, 0, 0, 964, 965, 7, 7, 0, 0, 965, 966, 7, 5, 0, 0, 966, 140, 1, 0, 0, 0, 967, 968, 7, 9, 0, 0, 968, 969, 7, 20, 0, 0, 969, 970, 7, 13, 0, 0, 970, 971, 7, 13, 0, 0, 971, 142, 1, 0, 0, 0, 972, 973, 7, 9, 0, 0, 973, 974, 7, 20, 0, 0, 974, 975, 7, 13, 0, 0, 975, 976, 7, 13, 0, 0, 976, 977, 7, 2, 0, 0, 977, 144, 1, 0, 0, 0, 978, 979, 7, 7, 0, 0, 979, 980, 7, 6, 0, 0, 980, 146, 1, 0, 0, 0, 981, 982, 5, 63, 0, 0, 982, 148, 1, 0, 0, 0, 983, 984, 7, 6, 0, 0, 984, 985, 7, 13, 0, 0, 985, 986, 7, 1, 0, 0, 986, 987, 7, 18, 0, 0, 987, 988, 7, 3, 0, 0, 988, 150, 1, 0, 0, 0, 989, 990, 5, 41, 0, 0, 990, 152, 1, 0, 0, 0, 991, 992, 7, 5, 0, 0, 992, 993, 7, 6, 0, 0, 993, 994, 7, 20, 0, 0, 994, 995, 7, 3, 0, 0, 995, 154, 1, 0, 0, 0, 996, 997, 5, 61, 0, 0, 997, 998, 5, 61, 0, 0, 998, 156, 1, 0, 0, 0, 999, 1000, 5, 61, 0, 0, 1000, 1001, 5, 126, 0, 0, 1001, 158, 1, 0, 0, 0, 1002, 1003, 5, 33, 0, 0, 1003, 1004, 5, 61, 0, 0, 1004, 160, 1, 0, 0, 0, 1005, 1006, 5, 60, 0, 0, 1006, 162, 1, 0, 0, 0, 1007, 1008, 5, 60, 0, 0, 1008, 1009, 5, 61, 0, 0, 1009, 164, 1, 0, 0, 0, 1010, 1011, 5, 62, 0, 0, 1011, 166, 1, 0, 0, 0, 1012, 1013, 5, 62, 0, 0, 1013, 1014, 5, 61, 0, 0, 1014, 168, 1, 0, 0, 0, 1015, 1016, 5, 43, 0, 0, 1016, 170, 1, 0, 0, 0, 1017, 1018, 5, 45, 0, 0, 1018, 172, 1, 0, 0, 0, 1019, 1020, 5, 42, 0, 0, 1020, 174, 1, 0, 0, 0, 1021, 1022, 5, 47, 0, 0, 1022, 176, 1, 0, 0, 0, 1023, 1024, 5, 37, 0, 0, 1024, 178, 1, 0, 0, 0, 1025, 1026, 5, 123, 0, 0, 1026, 180, 1, 0, 0, 0, 1027, 1028, 5, 125, 0, 0, 1028, 182, 1, 0, 0, 0, 1029, 1030, 3, 49, 15, 0, 1030, 1031, 1, 0, 0, 0, 1031, 1032, 6, 82, 15, 0, 1032, 184, 1, 0, 0, 0, 1033, 1034, 4, 83, 9, 0, 1034, 1035, 3, 45, 13, 0, 1035, 1036, 1, 0, 0, 0, 1036, 1037, 6, 83, 16, 0, 1037, 186, 1, 0, 0, 0, 1038, 1039, 4, 84, 10, 0, 1039, 1040, 3, 35, 8, 0, 1040, 1041, 1, 0, 0, 0, 1041, 1042, 6, 84, 17, 0, 1042, 188, 1, 0, 0, 0, 1043, 1046, 3, 147, 64, 0, 1044, 1047, 3, 83, 32, 0, 1045, 1047, 3, 97, 39, 0, 1046, 1044, 1, 0, 0, 0, 1046, 1045, 1, 0, 0, 0, 1047, 1051, 1, 0, 0, 0, 1048, 1050, 3, 99, 40, 0, 1049, 1048, 1, 0, 0, 0, 1050, 1053, 1, 0, 0, 0, 1051, 1049, 1, 0, 0, 0, 1051, 1052, 1, 0, 0, 0, 1052, 1061, 1, 0, 0, 0, 1053, 1051, 1, 0, 0, 0, 1054, 1056, 3, 147, 64, 0, 1055, 1057, 3, 81, 31, 0, 1056, 1055, 1, 0, 0, 0, 1057, 1058, 1, 0, 0, 0, 1058, 1056, 1, 0, 0, 0, 1058, 1059, 1, 0, 0, 0, 1059, 1061, 1, 0, 0, 0, 1060, 1043, 1, 0, 0, 0, 1060, 1054, 1, 0, 0, 0, 1061, 190, 1, 0, 0, 0, 1062, 1063, 5, 91, 0, 0, 1063, 1064, 1, 0, 0, 0, 1064, 1065, 6, 86, 0, 0, 1065, 1066, 6, 86, 0, 0, 1066, 192, 1, 0, 0, 0, 1067, 1068, 5, 93, 0, 0, 1068, 1069, 1, 0, 0, 0, 1069, 1070, 6, 87, 14, 0, 1070, 1071, 6, 87, 14, 0, 1071, 194, 1, 0, 0, 0, 1072, 1076, 3, 83, 32, 0, 1073, 1075, 3, 99, 40, 0, 1074, 1073, 1, 0, 0, 0, 1075, 1078, 1, 0, 0, 0, 1076, 1074, 1, 0, 0, 0, 1076, 1077, 1, 0, 0, 0, 1077, 1089, 1, 0, 0, 0, 1078, 1076, 1, 0, 0, 0, 1079, 1082, 3, 97, 39, 0, 1080, 1082, 3, 91, 36, 0, 1081, 1079, 1, 0, 0, 0, 1081, 1080, 1, 0, 0, 0, 1082, 1084, 1, 0, 0, 0, 1083, 1085, 3, 99, 40, 0, 1084, 1083, 1, 0, 0, 0, 1085, 1086, 1, 0, 0, 0, 1086, 1084, 1, 0, 0, 0, 1086, 1087, 1, 0, 0, 0, 1087, 1089, 1, 0, 0, 0, 1088, 1072, 1, 0, 0, 0, 1088, 1081, 1, 0, 0, 0, 1089, 196, 1, 0, 0, 0, 1090, 1092, 3, 93, 37, 0, 1091, 1093, 3, 95, 38, 0, 1092, 1091, 1, 0, 0, 0, 1093, 1094, 1, 0, 0, 0, 1094, 1092, 1, 0, 0, 0, 1094, 1095, 1, 0, 0, 0, 1095, 1096, 1, 0, 0, 0, 1096, 1097, 3, 93, 37, 0, 1097, 198, 1, 0, 0, 0, 1098, 1099, 3, 197, 89, 0, 1099, 200, 1, 0, 0, 0, 1100, 1101, 3, 73, 27, 0, 1101, 1102, 1, 0, 0, 0, 1102, 1103, 6, 91, 13, 0, 1103, 202, 1, 0, 0, 0, 1104, 1105, 3, 75, 28, 0, 1105, 1106, 1, 0, 0, 0, 1106, 1107, 6, 92, 13, 0, 1107, 204, 1, 0, 0, 0, 1108, 1109, 3, 77, 29, 0, 1109, 1110, 1, 0, 0, 0, 1110, 1111, 6, 93, 13, 0, 1111, 206, 1, 0, 0, 0, 1112, 1113, 3, 191, 86, 0, 1113, 1114, 1, 0, 0, 0, 1114, 1115, 6, 94, 18, 0, 1115, 1116, 6, 94, 19, 0, 1116, 208, 1, 0, 0, 0, 1117, 1118, 3, 79, 30, 0, 1118, 1119, 1, 0, 0, 0, 1119, 1120, 6, 95, 20, 0, 1120, 1121, 6, 95, 14, 0, 1121, 210, 1, 0, 0, 0, 1122, 1123, 3, 77, 29, 0, 1123, 1124, 1, 0, 0, 0, 1124, 1125, 6, 96, 13, 0, 1125, 212, 1, 0, 0, 0, 1126, 1127, 3, 73, 27, 0, 1127, 1128, 1, 0, 0, 0, 1128, 1129, 6, 97, 13, 0, 1129, 214, 1, 0, 0, 0, 1130, 1131, 3, 75, 28, 0, 1131, 1132, 1, 0, 0, 0, 1132, 1133, 6, 98, 13, 0, 1133, 216, 1, 0, 0, 0, 1134, 1135, 3, 79, 30, 0, 1135, 1136, 1, 0, 0, 0, 1136, 1137, 6, 99, 20, 0, 1137, 1138, 6, 99, 14, 0, 1138, 218, 1, 0, 0, 0, 1139, 1140, 3, 191, 86, 0, 1140, 1141, 1, 0, 0, 0, 1141, 1142, 6, 100, 18, 0, 1142, 220, 1, 0, 0, 0, 1143, 1144, 3, 193, 87, 0, 1144, 1145, 1, 0, 0, 0, 1145, 1146, 6, 101, 21, 0, 1146, 222, 1, 0, 0, 0, 1147, 1148, 3, 117, 49, 0, 1148, 1149, 1, 0, 0, 0, 1149, 1150, 6, 102, 22, 0, 1150, 224, 1, 0, 0, 0, 1151, 1152, 3, 119, 50, 0, 1152, 1153, 1, 0, 0, 0, 1153, 1154, 6, 103, 23, 0, 1154, 226, 1, 0, 0, 0, 1155, 1156, 3, 113, 47, 0, 1156, 1157, 1, 0, 0, 0, 1157, 1158, 6, 104, 24, 0, 1158, 228, 1, 0, 0, 0, 1159, 1160, 7, 16, 0, 0, 1160, 1161, 7, 3, 0, 0, 1161, 1162, 7, 5, 0, 0, 1162, 1163, 7, 12, 0, 0, 1163, 1164, 7, 0, 0, 0, 1164, 1165, 7, 12, 0, 0, 1165, 1166, 7, 5, 0, 0, 1166, 1167, 7, 12, 0, 0, 1167, 230, 1, 0, 0, 0, 1168, 1172, 8, 32, 0, 0, 1169, 1170, 5, 47, 0, 0, 1170, 1172, 8, 33, 0, 0, 1171, 1168, 1, 0, 0, 0, 1171, 1169, 1, 0, 0, 0, 1172, 232, 1, 0, 0, 0, 1173, 1175, 3, 231, 106, 0, 1174, 1173, 1, 0, 0, 0, 1175, 1176, 1, 0, 0, 0, 1176, 1174, 1, 0, 0, 0, 1176, 1177, 1, 0, 0, 0, 1177, 234, 1, 0, 0, 0, 1178, 1179, 3, 233, 107, 0, 1179, 1180, 1, 0, 0, 0, 1180, 1181, 6, 108, 25, 0, 1181, 236, 1, 0, 0, 0, 1182, 1183, 3, 101, 41, 0, 1183, 1184, 1, 0, 0, 0, 1184, 1185, 6, 109, 26, 0, 1185, 238, 1, 0, 0, 0, 1186, 1187, 3, 73, 27, 0, 1187, 1188, 1, 0, 0, 0, 1188, 1189, 6, 110, 13, 0, 1189, 240, 1, 0, 0, 0, 1190, 1191, 3, 75, 28, 0, 1191, 1192, 1, 0, 0, 0, 1192, 1193, 6, 111, 13, 0, 1193, 242, 1, 0, 0, 0, 1194, 1195, 3, 77, 29, 0, 1195, 1196, 1, 0, 0, 0, 1196, 1197, 6, 112, 13, 0, 1197, 244, 1, 0, 0, 0, 1198, 1199, 3, 79, 30, 0, 1199, 1200, 1, 0, 0, 0, 1200, 1201, 6, 113, 20, 0, 1201, 1202, 6, 113, 14, 0, 1202, 246, 1, 0, 0, 0, 1203, 1204, 3, 123, 52, 0, 1204, 1205, 1, 0, 0, 0, 1205, 1206, 6, 114, 27, 0, 1206, 248, 1, 0, 0, 0, 1207, 1208, 3, 119, 50, 0, 1208, 1209, 1, 0, 0, 0, 1209, 1210, 6, 115, 23, 0, 1210, 250, 1, 0, 0, 0, 1211, 1212, 3, 147, 64, 0, 1212, 1213, 1, 0, 0, 0, 1213, 1214, 6, 116, 28, 0, 1214, 252, 1, 0, 0, 0, 1215, 1216, 3, 189, 85, 0, 1216, 1217, 1, 0, 0, 0, 1217, 1218, 6, 117, 29, 0, 1218, 254, 1, 0, 0, 0, 1219, 1224, 3, 83, 32, 0, 1220, 1224, 3, 81, 31, 0, 1221, 1224, 3, 97, 39, 0, 1222, 1224, 3, 173, 77, 0, 1223, 1219, 1, 0, 0, 0, 1223, 1220, 1, 0, 0, 0, 1223, 1221, 1, 0, 0, 0, 1223, 1222, 1, 0, 0, 0, 1224, 256, 1, 0, 0, 0, 1225, 1228, 3, 83, 32, 0, 1226, 1228, 3, 173, 77, 0, 1227, 1225, 1, 0, 0, 0, 1227, 1226, 1, 0, 0, 0, 1228, 1232, 1, 0, 0, 0, 1229, 1231, 3, 255, 118, 0, 1230, 1229, 1, 0, 0, 0, 1231, 1234, 1, 0, 0, 0, 1232, 1230, 1, 0, 0, 0, 1232, 1233, 1, 0, 0, 0, 1233, 1245, 1, 0, 0, 0, 1234, 1232, 1, 0, 0, 0, 1235, 1238, 3, 97, 39, 0, 1236, 1238, 3, 91, 36, 0, 1237, 1235, 1, 0, 0, 0, 1237, 1236, 1, 0, 0, 0, 1238, 1240, 1, 0, 0, 0, 1239, 1241, 3, 255, 118, 0, 1240, 1239, 1, 0, 0, 0, 1241, 1242, 1, 0, 0, 0, 1242, 1240, 1, 0, 0, 0, 1242, 1243, 1, 0, 0, 0, 1243, 1245, 1, 0, 0, 0, 1244, 1227, 1, 0, 0, 0, 1244, 1237, 1, 0, 0, 0, 1245, 258, 1, 0, 0, 0, 1246, 1249, 3, 257, 119, 0, 1247, 1249, 3, 197, 89, 0, 1248, 1246, 1, 0, 0, 0, 1248, 1247, 1, 0, 0, 0, 1249, 1250, 1, 0, 0, 0, 1250, 1248, 1, 0, 0, 0, 1250, 1251, 1, 0, 0, 0, 1251, 260, 1, 0, 0, 0, 1252, 1253, 3, 73, 27, 0, 1253, 1254, 1, 0, 0, 0, 1254, 1255, 6, 121, 13, 0, 1255, 262, 1, 0, 0, 0, 1256, 1257, 3, 75, 28, 0, 1257, 1258, 1, 0, 0, 0, 1258, 1259, 6, 122, 13, 0, 1259, 264, 1, 0, 0, 0, 1260, 1261, 3, 77, 29, 0, 1261, 1262, 1, 0, 0, 0, 1262, 1263, 6, 123, 13, 0, 1263, 266, 1, 0, 0, 0, 1264, 1265, 3, 79, 30, 0, 1265, 1266, 1, 0, 0, 0, 1266, 1267, 6, 124, 20, 0, 1267, 1268, 6, 124, 14, 0, 1268, 268, 1, 0, 0, 0, 1269, 1270, 3, 113, 47, 0, 1270, 1271, 1, 0, 0, 0, 1271, 1272, 6, 125, 24, 0, 1272, 270, 1, 0, 0, 0, 1273, 1274, 3, 119, 50, 0, 1274, 1275, 1, 0, 0, 0, 1275, 1276, 6, 126, 23, 0, 1276, 272, 1, 0, 0, 0, 1277, 1278, 3, 123, 52, 0, 1278, 1279, 1, 0, 0, 0, 1279, 1280, 6, 127, 27, 0, 1280, 274, 1, 0, 0, 0, 1281, 1282, 3, 147, 64, 0, 1282, 1283, 1, 0, 0, 0, 1283, 1284, 6, 128, 28, 0, 1284, 276, 1, 0, 0, 0, 1285, 1286, 3, 189, 85, 0, 1286, 1287, 1, 0, 0, 0, 1287, 1288, 6, 129, 29, 0, 1288, 278, 1, 0, 0, 0, 1289, 1290, 7, 12, 0, 0, 1290, 1291, 7, 2, 0, 0, 1291, 280, 1, 0, 0, 0, 1292, 1293, 3, 259, 120, 0, 1293, 1294, 1, 0, 0, 0, 1294, 1295, 6, 131, 30, 0, 1295, 282, 1, 0, 0, 0, 1296, 1297, 3, 73, 27, 0, 1297, 1298, 1, 0, 0, 0, 1298, 1299, 6, 132, 13, 0, 1299, 284, 1, 0, 0, 0, 1300, 1301, 3, 75, 28, 0, 1301, 1302, 1, 0, 0, 0, 1302, 1303, 6, 133, 13, 0, 1303, 286, 1, 0, 0, 0, 1304, 1305, 3, 77, 29, 0, 1305, 1306, 1, 0, 0, 0, 1306, 1307, 6, 134, 13, 0, 1307, 288, 1, 0, 0, 0, 1308, 1309, 3, 79, 30, 0, 1309, 1310, 1, 0, 0, 0, 1310, 1311, 6, 135, 20, 0, 1311, 1312, 6, 135, 14, 0, 1312, 290, 1, 0, 0, 0, 1313, 1314, 3, 191, 86, 0, 1314, 1315, 1, 0, 0, 0, 1315, 1316, 6, 136, 18, 0, 1316, 1317, 6, 136, 31, 0, 1317, 292, 1, 0, 0, 0, 1318, 1319, 7, 7, 0, 0, 1319, 1320, 7, 9, 0, 0, 1320, 1321, 1, 0, 0, 0, 1321, 1322, 6, 137, 32, 0, 1322, 294, 1, 0, 0, 0, 1323, 1324, 7, 19, 0, 0, 1324, 1325, 7, 1, 0, 0, 1325, 1326, 7, 5, 0, 0, 1326, 1327, 7, 10, 0, 0, 1327, 1328, 1, 0, 0, 0, 1328, 1329, 6, 138, 32, 0, 1329, 296, 1, 0, 0, 0, 1330, 1331, 8, 34, 0, 0, 1331, 298, 1, 0, 0, 0, 1332, 1334, 3, 297, 139, 0, 1333, 1332, 1, 0, 0, 0, 1334, 1335, 1, 0, 0, 0, 1335, 1333, 1, 0, 0, 0, 1335, 1336, 1, 0, 0, 0, 1336, 1337, 1, 0, 0, 0, 1337, 1338, 3, 117, 49, 0, 1338, 1340, 1, 0, 0, 0, 1339, 1333, 1, 0, 0, 0, 1339, 1340, 1, 0, 0, 0, 1340, 1342, 1, 0, 0, 0, 1341, 1343, 3, 297, 139, 0, 1342, 1341, 1, 0, 0, 0, 1343, 1344, 1, 0, 0, 0, 1344, 1342, 1, 0, 0, 0, 1344, 1345, 1, 0, 0, 0, 1345, 300, 1, 0, 0, 0, 1346, 1347, 3, 299, 140, 0, 1347, 1348, 1, 0, 0, 0, 1348, 1349, 6, 141, 33, 0, 1349, 302, 1, 0, 0, 0, 1350, 1351, 3, 73, 27, 0, 1351, 1352, 1, 0, 0, 0, 1352, 1353, 6, 142, 13, 0, 1353, 304, 1, 0, 0, 0, 1354, 1355, 3, 75, 28, 0, 1355, 1356, 1, 0, 0, 0, 1356, 1357, 6, 143, 13, 0, 1357, 306, 1, 0, 0, 0, 1358, 1359, 3, 77, 29, 0, 1359, 1360, 1, 0, 0, 0, 1360, 1361, 6, 144, 13, 0, 1361, 308, 1, 0, 0, 0, 1362, 1363, 3, 79, 30, 0, 1363, 1364, 1, 0, 0, 0, 1364, 1365, 6, 145, 20, 0, 1365, 1366, 6, 145, 14, 0, 1366, 1367, 6, 145, 14, 0, 1367, 310, 1, 0, 0, 0, 1368, 1369, 3, 113, 47, 0, 1369, 1370, 1, 0, 0, 0, 1370, 1371, 6, 146, 24, 0, 1371, 312, 1, 0, 0, 0, 1372, 1373, 3, 119, 50, 0, 1373, 1374, 1, 0, 0, 0, 1374, 1375, 6, 147, 23, 0, 1375, 314, 1, 0, 0, 0, 1376, 1377, 3, 123, 52, 0, 1377, 1378, 1, 0, 0, 0, 1378, 1379, 6, 148, 27, 0, 1379, 316, 1, 0, 0, 0, 1380, 1381, 3, 295, 138, 0, 1381, 1382, 1, 0, 0, 0, 1382, 1383, 6, 149, 34, 0, 1383, 318, 1, 0, 0, 0, 1384, 1385, 3, 259, 120, 0, 1385, 1386, 1, 0, 0, 0, 1386, 1387, 6, 150, 30, 0, 1387, 320, 1, 0, 0, 0, 1388, 1389, 3, 199, 90, 0, 1389, 1390, 1, 0, 0, 0, 1390, 1391, 6, 151, 35, 0, 1391, 322, 1, 0, 0, 0, 1392, 1393, 3, 147, 64, 0, 1393, 1394, 1, 0, 0, 0, 1394, 1395, 6, 152, 28, 0, 1395, 324, 1, 0, 0, 0, 1396, 1397, 3, 189, 85, 0, 1397, 1398, 1, 0, 0, 0, 1398, 1399, 6, 153, 29, 0, 1399, 326, 1, 0, 0, 0, 1400, 1401, 3, 73, 27, 0, 1401, 1402, 1, 0, 0, 0, 1402, 1403, 6, 154, 13, 0, 1403, 328, 1, 0, 0, 0, 1404, 1405, 3, 75, 28, 0, 1405, 1406, 1, 0, 0, 0, 1406, 1407, 6, 155, 13, 0, 1407, 330, 1, 0, 0, 0, 1408, 1409, 3, 77, 29, 0, 1409, 1410, 1, 0, 0, 0, 1410, 1411, 6, 156, 13, 0, 1411, 332, 1, 0, 0, 0, 1412, 1413, 3, 79, 30, 0, 1413, 1414, 1, 0, 0, 0, 1414, 1415, 6, 157, 20, 0, 1415, 1416, 6, 157, 14, 0, 1416, 334, 1, 0, 0, 0, 1417, 1418, 3, 123, 52, 0, 1418, 1419, 1, 0, 0, 0, 1419, 1420, 6, 158, 27, 0, 1420, 336, 1, 0, 0, 0, 1421, 1422, 3, 147, 64, 0, 1422, 1423, 1, 0, 0, 0, 1423, 1424, 6, 159, 28, 0, 1424, 338, 1, 0, 0, 0, 1425, 1426, 3, 189, 85, 0, 1426, 1427, 1, 0, 0, 0, 1427, 1428, 6, 160, 29, 0, 1428, 340, 1, 0, 0, 0, 1429, 1430, 3, 199, 90, 0, 1430, 1431, 1, 0, 0, 0, 1431, 1432, 6, 161, 35, 0, 1432, 342, 1, 0, 0, 0, 1433, 1434, 3, 195, 88, 0, 1434, 1435, 1, 0, 0, 0, 1435, 1436, 6, 162, 36, 0, 1436, 344, 1, 0, 0, 0, 1437, 1438, 3, 73, 27, 0, 1438, 1439, 1, 0, 0, 0, 1439, 1440, 6, 163, 13, 0, 1440, 346, 1, 0, 0, 0, 1441, 1442, 3, 75, 28, 0, 1442, 1443, 1, 0, 0, 0, 1443, 1444, 6, 164, 13, 0, 1444, 348, 1, 0, 0, 0, 1445, 1446, 3, 77, 29, 0, 1446, 1447, 1, 0, 0, 0, 1447, 1448, 6, 165, 13, 0, 1448, 350, 1, 0, 0, 0, 1449, 1450, 3, 79, 30, 0, 1450, 1451, 1, 0, 0, 0, 1451, 1452, 6, 166, 20, 0, 1452, 1453, 6, 166, 14, 0, 1453, 352, 1, 0, 0, 0, 1454, 1455, 7, 1, 0, 0, 1455, 1456, 7, 9, 0, 0, 1456, 1457, 7, 15, 0, 0, 1457, 1458, 7, 7, 0, 0, 1458, 354, 1, 0, 0, 0, 1459, 1460, 3, 73, 27, 0, 1460, 1461, 1, 0, 0, 0, 1461, 1462, 6, 168, 13, 0, 1462, 356, 1, 0, 0, 0, 1463, 1464, 3, 75, 28, 0, 1464, 1465, 1, 0, 0, 0, 1465, 1466, 6, 169, 13, 0, 1466, 358, 1, 0, 0, 0, 1467, 1468, 3, 77, 29, 0, 1468, 1469, 1, 0, 0, 0, 1469, 1470, 6, 170, 13, 0, 1470, 360, 1, 0, 0, 0, 1471, 1472, 3, 193, 87, 0, 1472, 1473, 1, 0, 0, 0, 1473, 1474, 6, 171, 21, 0, 1474, 1475, 6, 171, 14, 0, 1475, 362, 1, 0, 0, 0, 1476, 1477, 3, 117, 49, 0, 1477, 1478, 1, 0, 0, 0, 1478, 1479, 6, 172, 22, 0, 1479, 364, 1, 0, 0, 0, 1480, 1486, 3, 91, 36, 0, 1481, 1486, 3, 81, 31, 0, 1482, 1486, 3, 123, 52, 0, 1483, 1486, 3, 83, 32, 0, 1484, 1486, 3, 97, 39, 0, 1485, 1480, 1, 0, 0, 0, 1485, 1481, 1, 0, 0, 0, 1485, 1482, 1, 0, 0, 0, 1485, 1483, 1, 0, 0, 0, 1485, 1484, 1, 0, 0, 0, 1486, 1487, 1, 0, 0, 0, 1487, 1485, 1, 0, 0, 0, 1487, 1488, 1, 0, 0, 0, 1488, 366, 1, 0, 0, 0, 1489, 1490, 3, 73, 27, 0, 1490, 1491, 1, 0, 0, 0, 1491, 1492, 6, 174, 13, 0, 1492, 368, 1, 0, 0, 0, 1493, 1494, 3, 75, 28, 0, 1494, 1495, 1, 0, 0, 0, 1495, 1496, 6, 175, 13, 0, 1496, 370, 1, 0, 0, 0, 1497, 1498, 3, 77, 29, 0, 1498, 1499, 1, 0, 0, 0, 1499, 1500, 6, 176, 13, 0, 1500, 372, 1, 0, 0, 0, 1501, 1502, 3, 79, 30, 0, 1502, 1503, 1, 0, 0, 0, 1503, 1504, 6, 177, 20, 0, 1504, 1505, 6, 177, 14, 0, 1505, 374, 1, 0, 0, 0, 1506, 1507, 3, 117, 49, 0, 1507, 1508, 1, 0, 0, 0, 1508, 1509, 6, 178, 22, 0, 1509, 376, 1, 0, 0, 0, 1510, 1511, 3, 119, 50, 0, 1511, 1512, 1, 0, 0, 0, 1512, 1513, 6, 179, 23, 0, 1513, 378, 1, 0, 0, 0, 1514, 1515, 3, 123, 52, 0, 1515, 1516, 1, 0, 0, 0, 1516, 1517, 6, 180, 27, 0, 1517, 380, 1, 0, 0, 0, 1518, 1519, 3, 293, 137, 0, 1519, 1520, 1, 0, 0, 0, 1520, 1521, 6, 181, 37, 0, 1521, 1522, 6, 181, 38, 0, 1522, 382, 1, 0, 0, 0, 1523, 1524, 3, 233, 107, 0, 1524, 1525, 1, 0, 0, 0, 1525, 1526, 6, 182, 25, 0, 1526, 384, 1, 0, 0, 0, 1527, 1528, 3, 101, 41, 0, 1528, 1529, 1, 0, 0, 0, 1529, 1530, 6, 183, 26, 0, 1530, 386, 1, 0, 0, 0, 1531, 1532, 3, 73, 27, 0, 1532, 1533, 1, 0, 0, 0, 1533, 1534, 6, 184, 13, 0, 1534, 388, 1, 0, 0, 0, 1535, 1536, 3, 75, 28, 0, 1536, 1537, 1, 0, 0, 0, 1537, 1538, 6, 185, 13, 0, 1538, 390, 1, 0, 0, 0, 1539, 1540, 3, 77, 29, 0, 1540, 1541, 1, 0, 0, 0, 1541, 1542, 6, 186, 13, 0, 1542, 392, 1, 0, 0, 0, 1543, 1544, 3, 79, 30, 0, 1544, 1545, 1, 0, 0, 0, 1545, 1546, 6, 187, 20, 0, 1546, 1547, 6, 187, 14, 0, 1547, 1548, 6, 187, 14, 0, 1548, 394, 1, 0, 0, 0, 1549, 1550, 3, 119, 50, 0, 1550, 1551, 1, 0, 0, 0, 1551, 1552, 6, 188, 23, 0, 1552, 396, 1, 0, 0, 0, 1553, 1554, 3, 123, 52, 0, 1554, 1555, 1, 0, 0, 0, 1555, 1556, 6, 189, 27, 0, 1556, 398, 1, 0, 0, 0, 1557, 1558, 3, 259, 120, 0, 1558, 1559, 1, 0, 0, 0, 1559, 1560, 6, 190, 30, 0, 1560, 400, 1, 0, 0, 0, 1561, 1562, 3, 73, 27, 0, 1562, 1563, 1, 0, 0, 0, 1563, 1564, 6, 191, 13, 0, 1564, 402, 1, 0, 0, 0, 1565, 1566, 3, 75, 28, 0, 1566, 1567, 1, 0, 0, 0, 1567, 1568, 6, 192, 13, 0, 1568, 404, 1, 0, 0, 0, 1569, 1570, 3, 77, 29, 0, 1570, 1571, 1, 0, 0, 0, 1571, 1572, 6, 193, 13, 0, 1572, 406, 1, 0, 0, 0, 1573, 1574, 3, 79, 30, 0, 1574, 1575, 1, 0, 0, 0, 1575, 1576, 6, 194, 20, 0, 1576, 1577, 6, 194, 14, 0, 1577, 408, 1, 0, 0, 0, 1578, 1579, 7, 35, 0, 0, 1579, 1580, 7, 7, 0, 0, 1580, 1581, 7, 1, 0, 0, 1581, 1582, 7, 9, 0, 0, 1582, 410, 1, 0, 0, 0, 1583, 1584, 3, 279, 130, 0, 1584, 1585, 1, 0, 0, 0, 1585, 1586, 6, 196, 39, 0, 1586, 412, 1, 0, 0, 0, 1587, 1588, 3, 293, 137, 0, 1588, 1589, 1, 0, 0, 0, 1589, 1590, 6, 197, 37, 0, 1590, 1591, 6, 197, 14, 0, 1591, 1592, 6, 197, 0, 0, 1592, 414, 1, 0, 0, 0, 1593, 1594, 7, 20, 0, 0, 1594, 1595, 7, 2, 0, 0, 1595, 1596, 7, 1, 0, 0, 1596, 1597, 7, 9, 0, 0, 1597, 1598, 7, 17, 0, 0, 1598, 1599, 1, 0, 0, 0, 1599, 1600, 6, 198, 14, 0, 1600, 1601, 6, 198, 0, 0, 1601, 416, 1, 0, 0, 0, 1602, 1603, 3, 233, 107, 0, 1603, 1604, 1, 0, 0, 0, 1604, 1605, 6, 199, 25, 0, 1605, 418, 1, 0, 0, 0, 1606, 1607, 3, 101, 41, 0, 1607, 1608, 1, 0, 0, 0, 1608, 1609, 6, 200, 26, 0, 1609, 420, 1, 0, 0, 0, 1610, 1611, 3, 117, 49, 0, 1611, 1612, 1, 0, 0, 0, 1612, 1613, 6, 201, 22, 0, 1613, 422, 1, 0, 0, 0, 1614, 1615, 3, 195, 88, 0, 1615, 1616, 1, 0, 0, 0, 1616, 1617, 6, 202, 36, 0, 1617, 424, 1, 0, 0, 0, 1618, 1619, 3, 199, 90, 0, 1619, 1620, 1, 0, 0, 0, 1620, 1621, 6, 203, 35, 0, 1621, 426, 1, 0, 0, 0, 1622, 1623, 3, 73, 27, 0, 1623, 1624, 1, 0, 0, 0, 1624, 1625, 6, 204, 13, 0, 1625, 428, 1, 0, 0, 0, 1626, 1627, 3, 75, 28, 0, 1627, 1628, 1, 0, 0, 0, 1628, 1629, 6, 205, 13, 0, 1629, 430, 1, 0, 0, 0, 1630, 1631, 3, 77, 29, 0, 1631, 1632, 1, 0, 0, 0, 1632, 1633, 6, 206, 13, 0, 1633, 432, 1, 0, 0, 0, 1634, 1635, 3, 79, 30, 0, 1635, 1636, 1, 0, 0, 0, 1636, 1637, 6, 207, 20, 0, 1637, 1638, 6, 207, 14, 0, 1638, 434, 1, 0, 0, 0, 1639, 1640, 3, 233, 107, 0, 1640, 1641, 1, 0, 0, 0, 1641, 1642, 6, 208, 25, 0, 1642, 1643, 6, 208, 14, 0, 1643, 1644, 6, 208, 40, 0, 1644, 436, 1, 0, 0, 0, 1645, 1646, 3, 101, 41, 0, 1646, 1647, 1, 0, 0, 0, 1647, 1648, 6, 209, 26, 0, 1648, 1649, 6, 209, 14, 0, 1649, 1650, 6, 209, 40, 0, 1650, 438, 1, 0, 0, 0, 1651, 1652, 3, 73, 27, 0, 1652, 1653, 1, 0, 0, 0, 1653, 1654, 6, 210, 13, 0, 1654, 440, 1, 0, 0, 0, 1655, 1656, 3, 75, 28, 0, 1656, 1657, 1, 0, 0, 0, 1657, 1658, 6, 211, 13, 0, 1658, 442, 1, 0, 0, 0, 1659, 1660, 3, 77, 29, 0, 1660, 1661, 1, 0, 0, 0, 1661, 1662, 6, 212, 13, 0, 1662, 444, 1, 0, 0, 0, 1663, 1664, 3, 117, 49, 0, 1664, 1665, 1, 0, 0, 0, 1665, 1666, 6, 213, 22, 0, 1666, 1667, 6, 213, 14, 0, 1667, 1668, 6, 213, 11, 0, 1668, 446, 1, 0, 0, 0, 1669, 1670, 3, 119, 50, 0, 1670, 1671, 1, 0, 0, 0, 1671, 1672, 6, 214, 23, 0, 1672, 1673, 6, 214, 14, 0, 1673, 1674, 6, 214, 11, 0, 1674, 448, 1, 0, 0, 0, 1675, 1676, 3, 73, 27, 0, 1676, 1677, 1, 0, 0, 0, 1677, 1678, 6, 215, 13, 0, 1678, 450, 1, 0, 0, 0, 1679, 1680, 3, 75, 28, 0, 1680, 1681, 1, 0, 0, 0, 1681, 1682, 6, 216, 13, 0, 1682, 452, 1, 0, 0, 0, 1683, 1684, 3, 77, 29, 0, 1684, 1685, 1, 0, 0, 0, 1685, 1686, 6, 217, 13, 0, 1686, 454, 1, 0, 0, 0, 1687, 1688, 3, 199, 90, 0, 1688, 1689, 1, 0, 0, 0, 1689, 1690, 6, 218, 14, 0, 1690, 1691, 6, 218, 0, 0, 1691, 1692, 6, 218, 35, 0, 1692, 456, 1, 0, 0, 0, 1693, 1694, 3, 195, 88, 0, 1694, 1695, 1, 0, 0, 0, 1695, 1696, 6, 219, 14, 0, 1696, 1697, 6, 219, 0, 0, 1697, 1698, 6, 219, 36, 0, 1698, 458, 1, 0, 0, 0, 1699, 1700, 3, 107, 44, 0, 1700, 1701, 1, 0, 0, 0, 1701, 1702, 6, 220, 14, 0, 1702, 1703, 6, 220, 0, 0, 1703, 1704, 6, 220, 41, 0, 1704, 460, 1, 0, 0, 0, 1705, 1706, 3, 79, 30, 0, 1706, 1707, 1, 0, 0, 0, 1707, 1708, 6, 221, 20, 0, 1708, 1709, 6, 221, 14, 0, 1709, 462, 1, 0, 0, 0, 1710, 1711, 3, 79, 30, 0, 1711, 1712, 1, 0, 0, 0, 1712, 1713, 6, 222, 20, 0, 1713, 1714, 6, 222, 14, 0, 1714, 464, 1, 0, 0, 0, 1715, 1716, 3, 293, 137, 0, 1716, 1717, 1, 0, 0, 0, 1717, 1718, 6, 223, 37, 0, 1718, 466, 1, 0, 0, 0, 1719, 1720, 3, 279, 130, 0, 1720, 1721, 1, 0, 0, 0, 1721, 1722, 6, 224, 39, 0, 1722, 468, 1, 0, 0, 0, 1723, 1724, 3, 123, 52, 0, 1724, 1725, 1, 0, 0, 0, 1725, 1726, 6, 225, 27, 0, 1726, 470, 1, 0, 0, 0, 1727, 1728, 3, 119, 50, 0, 1728, 1729, 1, 0, 0, 0, 1729, 1730, 6, 226, 23, 0, 1730, 472, 1, 0, 0, 0, 1731, 1732, 3, 199, 90, 0, 1732, 1733, 1, 0, 0, 0, 1733, 1734, 6, 227, 35, 0, 1734, 474, 1, 0, 0, 0, 1735, 1736, 3, 195, 88, 0, 1736, 1737, 1, 0, 0, 0, 1737, 1738, 6, 228, 36, 0, 1738, 476, 1, 0, 0, 0, 1739, 1740, 3, 73, 27, 0, 1740, 1741, 1, 0, 0, 0, 1741, 1742, 6, 229, 13, 0, 1742, 478, 1, 0, 0, 0, 1743, 1744, 3, 75, 28, 0, 1744, 1745, 1, 0, 0, 0, 1745, 1746, 6, 230, 13, 0, 1746, 480, 1, 0, 0, 0, 1747, 1748, 3, 77, 29, 0, 1748, 1749, 1, 0, 0, 0, 1749, 1750, 6, 231, 13, 0, 1750, 482, 1, 0, 0, 0, 1751, 1752, 3, 79, 30, 0, 1752, 1753, 1, 0, 0, 0, 1753, 1754, 6, 232, 20, 0, 1754, 1755, 6, 232, 14, 0, 1755, 484, 1, 0, 0, 0, 1756, 1757, 3, 195, 88, 0, 1757, 1758, 1, 0, 0, 0, 1758, 1759, 6, 233, 36, 0, 1759, 486, 1, 0, 0, 0, 1760, 1761, 3, 77, 29, 0, 1761, 1762, 1, 0, 0, 0, 1762, 1763, 6, 234, 13, 0, 1763, 488, 1, 0, 0, 0, 1764, 1765, 3, 73, 27, 0, 1765, 1766, 1, 0, 0, 0, 1766, 1767, 6, 235, 13, 0, 1767, 490, 1, 0, 0, 0, 1768, 1769, 3, 75, 28, 0, 1769, 1770, 1, 0, 0, 0, 1770, 1771, 6, 236, 13, 0, 1771, 492, 1, 0, 0, 0, 1772, 1773, 3, 137, 59, 0, 1773, 1774, 1, 0, 0, 0, 1774, 1775, 6, 237, 42, 0, 1775, 1776, 6, 237, 19, 0, 1776, 494, 1, 0, 0, 0, 1777, 1778, 3, 151, 66, 0, 1778, 1779, 1, 0, 0, 0, 1779, 1780, 6, 238, 43, 0, 1780, 1781, 6, 238, 14, 0, 1781, 496, 1, 0, 0, 0, 1782, 1783, 3, 79, 30, 0, 1783, 1784, 1, 0, 0, 0, 1784, 1785, 6, 239, 20, 0, 1785, 1786, 6, 239, 14, 0, 1786, 498, 1, 0, 0, 0, 1787, 1788, 3, 77, 29, 0, 1788, 1789, 1, 0, 0, 0, 1789, 1790, 6, 240, 13, 0, 1790, 500, 1, 0, 0, 0, 1791, 1792, 3, 73, 27, 0, 1792, 1793, 1, 0, 0, 0, 1793, 1794, 6, 241, 13, 0, 1794, 502, 1, 0, 0, 0, 1795, 1796, 3, 75, 28, 0, 1796, 1797, 1, 0, 0, 0, 1797, 1798, 6, 242, 13, 0, 1798, 504, 1, 0, 0, 0, 69, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 745, 755, 759, 762, 771, 773, 784, 803, 808, 817, 824, 829, 831, 842, 850, 853, 855, 860, 865, 871, 878, 883, 889, 892, 900, 904, 1046, 1051, 1058, 1060, 1076, 1081, 1086, 1088, 1094, 1171, 1176, 1223, 1227, 1232, 1237, 1242, 1244, 1248, 1250, 1335, 1339, 1344, 1485, 1487, 44, 5, 1, 0, 5, 4, 0, 5, 6, 0, 5, 2, 0, 5, 3, 0, 5, 8, 0, 5, 5, 0, 5, 9, 0, 5, 13, 0, 5, 16, 0, 5, 11, 0, 5, 14, 0, 5, 18, 0, 0, 1, 0, 4, 0, 0, 7, 16, 0, 7, 14, 0, 7, 9, 0, 7, 74, 0, 5, 0, 0, 7, 31, 0, 7, 75, 0, 7, 40, 0, 7, 41, 0, 7, 38, 0, 7, 85, 0, 7, 32, 0, 7, 43, 0, 7, 55, 0, 7, 73, 0, 7, 89, 0, 5, 10, 0, 5, 7, 0, 7, 99, 0, 7, 98, 0, 7, 77, 0, 7, 76, 0, 7, 97, 0, 5, 12, 0, 7, 93, 0, 5, 15, 0, 7, 35, 0, 7, 50, 0, 7, 57, 0] \ No newline at end of file +[4, 0, 142, 1784, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 6, -1, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 2, 73, 7, 73, 2, 74, 7, 74, 2, 75, 7, 75, 2, 76, 7, 76, 2, 77, 7, 77, 2, 78, 7, 78, 2, 79, 7, 79, 2, 80, 7, 80, 2, 81, 7, 81, 2, 82, 7, 82, 2, 83, 7, 83, 2, 84, 7, 84, 2, 85, 7, 85, 2, 86, 7, 86, 2, 87, 7, 87, 2, 88, 7, 88, 2, 89, 7, 89, 2, 90, 7, 90, 2, 91, 7, 91, 2, 92, 7, 92, 2, 93, 7, 93, 2, 94, 7, 94, 2, 95, 7, 95, 2, 96, 7, 96, 2, 97, 7, 97, 2, 98, 7, 98, 2, 99, 7, 99, 2, 100, 7, 100, 2, 101, 7, 101, 2, 102, 7, 102, 2, 103, 7, 103, 2, 104, 7, 104, 2, 105, 7, 105, 2, 106, 7, 106, 2, 107, 7, 107, 2, 108, 7, 108, 2, 109, 7, 109, 2, 110, 7, 110, 2, 111, 7, 111, 2, 112, 7, 112, 2, 113, 7, 113, 2, 114, 7, 114, 2, 115, 7, 115, 2, 116, 7, 116, 2, 117, 7, 117, 2, 118, 7, 118, 2, 119, 7, 119, 2, 120, 7, 120, 2, 121, 7, 121, 2, 122, 7, 122, 2, 123, 7, 123, 2, 124, 7, 124, 2, 125, 7, 125, 2, 126, 7, 126, 2, 127, 7, 127, 2, 128, 7, 128, 2, 129, 7, 129, 2, 130, 7, 130, 2, 131, 7, 131, 2, 132, 7, 132, 2, 133, 7, 133, 2, 134, 7, 134, 2, 135, 7, 135, 2, 136, 7, 136, 2, 137, 7, 137, 2, 138, 7, 138, 2, 139, 7, 139, 2, 140, 7, 140, 2, 141, 7, 141, 2, 142, 7, 142, 2, 143, 7, 143, 2, 144, 7, 144, 2, 145, 7, 145, 2, 146, 7, 146, 2, 147, 7, 147, 2, 148, 7, 148, 2, 149, 7, 149, 2, 150, 7, 150, 2, 151, 7, 151, 2, 152, 7, 152, 2, 153, 7, 153, 2, 154, 7, 154, 2, 155, 7, 155, 2, 156, 7, 156, 2, 157, 7, 157, 2, 158, 7, 158, 2, 159, 7, 159, 2, 160, 7, 160, 2, 161, 7, 161, 2, 162, 7, 162, 2, 163, 7, 163, 2, 164, 7, 164, 2, 165, 7, 165, 2, 166, 7, 166, 2, 167, 7, 167, 2, 168, 7, 168, 2, 169, 7, 169, 2, 170, 7, 170, 2, 171, 7, 171, 2, 172, 7, 172, 2, 173, 7, 173, 2, 174, 7, 174, 2, 175, 7, 175, 2, 176, 7, 176, 2, 177, 7, 177, 2, 178, 7, 178, 2, 179, 7, 179, 2, 180, 7, 180, 2, 181, 7, 181, 2, 182, 7, 182, 2, 183, 7, 183, 2, 184, 7, 184, 2, 185, 7, 185, 2, 186, 7, 186, 2, 187, 7, 187, 2, 188, 7, 188, 2, 189, 7, 189, 2, 190, 7, 190, 2, 191, 7, 191, 2, 192, 7, 192, 2, 193, 7, 193, 2, 194, 7, 194, 2, 195, 7, 195, 2, 196, 7, 196, 2, 197, 7, 197, 2, 198, 7, 198, 2, 199, 7, 199, 2, 200, 7, 200, 2, 201, 7, 201, 2, 202, 7, 202, 2, 203, 7, 203, 2, 204, 7, 204, 2, 205, 7, 205, 2, 206, 7, 206, 2, 207, 7, 207, 2, 208, 7, 208, 2, 209, 7, 209, 2, 210, 7, 210, 2, 211, 7, 211, 2, 212, 7, 212, 2, 213, 7, 213, 2, 214, 7, 214, 2, 215, 7, 215, 2, 216, 7, 216, 2, 217, 7, 217, 2, 218, 7, 218, 2, 219, 7, 219, 2, 220, 7, 220, 2, 221, 7, 221, 2, 222, 7, 222, 2, 223, 7, 223, 2, 224, 7, 224, 2, 225, 7, 225, 2, 226, 7, 226, 2, 227, 7, 227, 2, 228, 7, 228, 2, 229, 7, 229, 2, 230, 7, 230, 2, 231, 7, 231, 2, 232, 7, 232, 2, 233, 7, 233, 2, 234, 7, 234, 2, 235, 7, 235, 2, 236, 7, 236, 2, 237, 7, 237, 2, 238, 7, 238, 2, 239, 7, 239, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 17, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 19, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 21, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 23, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 24, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 25, 1, 26, 4, 26, 738, 8, 26, 11, 26, 12, 26, 739, 1, 26, 1, 26, 1, 27, 1, 27, 1, 27, 1, 27, 5, 27, 748, 8, 27, 10, 27, 12, 27, 751, 9, 27, 1, 27, 3, 27, 754, 8, 27, 1, 27, 3, 27, 757, 8, 27, 1, 27, 1, 27, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 5, 28, 766, 8, 28, 10, 28, 12, 28, 769, 9, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 28, 1, 29, 4, 29, 777, 8, 29, 11, 29, 12, 29, 778, 1, 29, 1, 29, 1, 30, 1, 30, 1, 30, 1, 30, 1, 31, 1, 31, 1, 32, 1, 32, 1, 33, 1, 33, 1, 33, 1, 34, 1, 34, 1, 35, 1, 35, 3, 35, 798, 8, 35, 1, 35, 4, 35, 801, 8, 35, 11, 35, 12, 35, 802, 1, 36, 1, 36, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 3, 38, 812, 8, 38, 1, 39, 1, 39, 1, 40, 1, 40, 1, 40, 3, 40, 819, 8, 40, 1, 41, 1, 41, 1, 41, 5, 41, 824, 8, 41, 10, 41, 12, 41, 827, 9, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 5, 41, 835, 8, 41, 10, 41, 12, 41, 838, 9, 41, 1, 41, 1, 41, 1, 41, 1, 41, 1, 41, 3, 41, 845, 8, 41, 1, 41, 3, 41, 848, 8, 41, 3, 41, 850, 8, 41, 1, 42, 4, 42, 853, 8, 42, 11, 42, 12, 42, 854, 1, 43, 4, 43, 858, 8, 43, 11, 43, 12, 43, 859, 1, 43, 1, 43, 5, 43, 864, 8, 43, 10, 43, 12, 43, 867, 9, 43, 1, 43, 1, 43, 4, 43, 871, 8, 43, 11, 43, 12, 43, 872, 1, 43, 4, 43, 876, 8, 43, 11, 43, 12, 43, 877, 1, 43, 1, 43, 5, 43, 882, 8, 43, 10, 43, 12, 43, 885, 9, 43, 3, 43, 887, 8, 43, 1, 43, 1, 43, 1, 43, 1, 43, 4, 43, 893, 8, 43, 11, 43, 12, 43, 894, 1, 43, 1, 43, 3, 43, 899, 8, 43, 1, 44, 1, 44, 1, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 1, 51, 1, 51, 1, 51, 1, 51, 1, 51, 1, 52, 1, 52, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 53, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 1, 58, 1, 59, 1, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 61, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 64, 1, 65, 1, 65, 1, 65, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 69, 1, 69, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 72, 1, 72, 1, 72, 1, 73, 1, 73, 1, 74, 1, 74, 1, 75, 1, 75, 1, 76, 1, 76, 1, 77, 1, 77, 1, 78, 1, 78, 1, 79, 1, 79, 1, 80, 1, 80, 1, 80, 1, 80, 1, 81, 1, 81, 1, 81, 3, 81, 1027, 8, 81, 1, 81, 5, 81, 1030, 8, 81, 10, 81, 12, 81, 1033, 9, 81, 1, 81, 1, 81, 4, 81, 1037, 8, 81, 11, 81, 12, 81, 1038, 3, 81, 1041, 8, 81, 1, 82, 1, 82, 1, 82, 1, 82, 1, 82, 1, 83, 1, 83, 1, 83, 1, 83, 1, 83, 1, 84, 1, 84, 1, 84, 1, 84, 1, 84, 1, 85, 1, 85, 1, 85, 1, 85, 1, 85, 1, 86, 1, 86, 5, 86, 1065, 8, 86, 10, 86, 12, 86, 1068, 9, 86, 1, 86, 1, 86, 3, 86, 1072, 8, 86, 1, 86, 4, 86, 1075, 8, 86, 11, 86, 12, 86, 1076, 3, 86, 1079, 8, 86, 1, 87, 1, 87, 4, 87, 1083, 8, 87, 11, 87, 12, 87, 1084, 1, 87, 1, 87, 1, 88, 1, 88, 1, 89, 1, 89, 1, 89, 1, 89, 1, 90, 1, 90, 1, 90, 1, 90, 1, 91, 1, 91, 1, 91, 1, 91, 1, 92, 1, 92, 1, 92, 1, 92, 1, 92, 1, 93, 1, 93, 1, 93, 1, 93, 1, 93, 1, 94, 1, 94, 1, 94, 1, 94, 1, 95, 1, 95, 1, 95, 1, 95, 1, 96, 1, 96, 1, 96, 1, 96, 1, 97, 1, 97, 1, 97, 1, 97, 1, 97, 1, 98, 1, 98, 1, 98, 1, 98, 1, 99, 1, 99, 1, 99, 1, 99, 1, 100, 1, 100, 1, 100, 1, 100, 1, 101, 1, 101, 1, 101, 1, 101, 1, 102, 1, 102, 1, 102, 1, 102, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 103, 1, 104, 1, 104, 1, 104, 3, 104, 1162, 8, 104, 1, 105, 4, 105, 1165, 8, 105, 11, 105, 12, 105, 1166, 1, 106, 1, 106, 1, 106, 1, 106, 1, 107, 1, 107, 1, 107, 1, 107, 1, 108, 1, 108, 1, 108, 1, 108, 1, 109, 1, 109, 1, 109, 1, 109, 1, 110, 1, 110, 1, 110, 1, 110, 1, 111, 1, 111, 1, 111, 1, 111, 1, 111, 1, 112, 1, 112, 1, 112, 1, 112, 1, 113, 1, 113, 1, 113, 1, 113, 1, 114, 1, 114, 1, 114, 1, 114, 1, 115, 1, 115, 1, 115, 1, 115, 1, 116, 1, 116, 1, 116, 1, 116, 3, 116, 1214, 8, 116, 1, 117, 1, 117, 3, 117, 1218, 8, 117, 1, 117, 5, 117, 1221, 8, 117, 10, 117, 12, 117, 1224, 9, 117, 1, 117, 1, 117, 3, 117, 1228, 8, 117, 1, 117, 4, 117, 1231, 8, 117, 11, 117, 12, 117, 1232, 3, 117, 1235, 8, 117, 1, 118, 1, 118, 4, 118, 1239, 8, 118, 11, 118, 12, 118, 1240, 1, 119, 1, 119, 1, 119, 1, 119, 1, 120, 1, 120, 1, 120, 1, 120, 1, 121, 1, 121, 1, 121, 1, 121, 1, 122, 1, 122, 1, 122, 1, 122, 1, 122, 1, 123, 1, 123, 1, 123, 1, 123, 1, 124, 1, 124, 1, 124, 1, 124, 1, 125, 1, 125, 1, 125, 1, 125, 1, 126, 1, 126, 1, 126, 1, 126, 1, 127, 1, 127, 1, 127, 1, 127, 1, 128, 1, 128, 1, 128, 1, 129, 1, 129, 1, 129, 1, 129, 1, 130, 1, 130, 1, 130, 1, 130, 1, 131, 1, 131, 1, 131, 1, 131, 1, 132, 1, 132, 1, 132, 1, 132, 1, 133, 1, 133, 1, 133, 1, 133, 1, 133, 1, 134, 1, 134, 1, 134, 1, 134, 1, 134, 1, 135, 1, 135, 1, 135, 1, 135, 1, 135, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 136, 1, 137, 1, 137, 1, 138, 4, 138, 1324, 8, 138, 11, 138, 12, 138, 1325, 1, 138, 1, 138, 3, 138, 1330, 8, 138, 1, 138, 4, 138, 1333, 8, 138, 11, 138, 12, 138, 1334, 1, 139, 1, 139, 1, 139, 1, 139, 1, 140, 1, 140, 1, 140, 1, 140, 1, 141, 1, 141, 1, 141, 1, 141, 1, 142, 1, 142, 1, 142, 1, 142, 1, 143, 1, 143, 1, 143, 1, 143, 1, 143, 1, 143, 1, 144, 1, 144, 1, 144, 1, 144, 1, 145, 1, 145, 1, 145, 1, 145, 1, 146, 1, 146, 1, 146, 1, 146, 1, 147, 1, 147, 1, 147, 1, 147, 1, 148, 1, 148, 1, 148, 1, 148, 1, 149, 1, 149, 1, 149, 1, 149, 1, 150, 1, 150, 1, 150, 1, 150, 1, 151, 1, 151, 1, 151, 1, 151, 1, 152, 1, 152, 1, 152, 1, 152, 1, 153, 1, 153, 1, 153, 1, 153, 1, 154, 1, 154, 1, 154, 1, 154, 1, 155, 1, 155, 1, 155, 1, 155, 1, 155, 1, 156, 1, 156, 1, 156, 1, 156, 1, 157, 1, 157, 1, 157, 1, 157, 1, 158, 1, 158, 1, 158, 1, 158, 1, 159, 1, 159, 1, 159, 1, 159, 1, 160, 1, 160, 1, 160, 1, 160, 1, 161, 1, 161, 1, 161, 1, 161, 1, 162, 1, 162, 1, 162, 1, 162, 1, 163, 1, 163, 1, 163, 1, 163, 1, 164, 1, 164, 1, 164, 1, 164, 1, 164, 1, 165, 1, 165, 1, 165, 1, 165, 1, 165, 1, 166, 1, 166, 1, 166, 1, 166, 1, 167, 1, 167, 1, 167, 1, 167, 1, 168, 1, 168, 1, 168, 1, 168, 1, 169, 1, 169, 1, 169, 1, 169, 1, 169, 1, 170, 1, 170, 1, 170, 1, 170, 1, 171, 1, 171, 1, 171, 1, 171, 1, 171, 4, 171, 1476, 8, 171, 11, 171, 12, 171, 1477, 1, 172, 1, 172, 1, 172, 1, 172, 1, 173, 1, 173, 1, 173, 1, 173, 1, 174, 1, 174, 1, 174, 1, 174, 1, 175, 1, 175, 1, 175, 1, 175, 1, 175, 1, 176, 1, 176, 1, 176, 1, 176, 1, 177, 1, 177, 1, 177, 1, 177, 1, 178, 1, 178, 1, 178, 1, 178, 1, 179, 1, 179, 1, 179, 1, 179, 1, 179, 1, 180, 1, 180, 1, 180, 1, 180, 1, 181, 1, 181, 1, 181, 1, 181, 1, 182, 1, 182, 1, 182, 1, 182, 1, 183, 1, 183, 1, 183, 1, 183, 1, 184, 1, 184, 1, 184, 1, 184, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, 185, 1, 186, 1, 186, 1, 186, 1, 186, 1, 187, 1, 187, 1, 187, 1, 187, 1, 188, 1, 188, 1, 188, 1, 188, 1, 189, 1, 189, 1, 189, 1, 189, 1, 190, 1, 190, 1, 190, 1, 190, 1, 191, 1, 191, 1, 191, 1, 191, 1, 192, 1, 192, 1, 192, 1, 192, 1, 192, 1, 193, 1, 193, 1, 193, 1, 193, 1, 193, 1, 194, 1, 194, 1, 194, 1, 194, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 195, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 196, 1, 197, 1, 197, 1, 197, 1, 197, 1, 198, 1, 198, 1, 198, 1, 198, 1, 199, 1, 199, 1, 199, 1, 199, 1, 200, 1, 200, 1, 200, 1, 200, 1, 201, 1, 201, 1, 201, 1, 201, 1, 202, 1, 202, 1, 202, 1, 202, 1, 203, 1, 203, 1, 203, 1, 203, 1, 204, 1, 204, 1, 204, 1, 204, 1, 205, 1, 205, 1, 205, 1, 205, 1, 205, 1, 206, 1, 206, 1, 206, 1, 206, 1, 206, 1, 206, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 207, 1, 208, 1, 208, 1, 208, 1, 208, 1, 209, 1, 209, 1, 209, 1, 209, 1, 210, 1, 210, 1, 210, 1, 210, 1, 211, 1, 211, 1, 211, 1, 211, 1, 211, 1, 211, 1, 212, 1, 212, 1, 212, 1, 212, 1, 212, 1, 212, 1, 213, 1, 213, 1, 213, 1, 213, 1, 214, 1, 214, 1, 214, 1, 214, 1, 215, 1, 215, 1, 215, 1, 215, 1, 216, 1, 216, 1, 216, 1, 216, 1, 216, 1, 216, 1, 217, 1, 217, 1, 217, 1, 217, 1, 217, 1, 217, 1, 218, 1, 218, 1, 218, 1, 218, 1, 218, 1, 218, 1, 219, 1, 219, 1, 219, 1, 219, 1, 219, 1, 220, 1, 220, 1, 220, 1, 220, 1, 220, 1, 221, 1, 221, 1, 221, 1, 221, 1, 222, 1, 222, 1, 222, 1, 222, 1, 223, 1, 223, 1, 223, 1, 223, 1, 224, 1, 224, 1, 224, 1, 224, 1, 225, 1, 225, 1, 225, 1, 225, 1, 226, 1, 226, 1, 226, 1, 226, 1, 227, 1, 227, 1, 227, 1, 227, 1, 228, 1, 228, 1, 228, 1, 228, 1, 229, 1, 229, 1, 229, 1, 229, 1, 230, 1, 230, 1, 230, 1, 230, 1, 230, 1, 231, 1, 231, 1, 231, 1, 231, 1, 232, 1, 232, 1, 232, 1, 232, 1, 233, 1, 233, 1, 233, 1, 233, 1, 234, 1, 234, 1, 234, 1, 234, 1, 235, 1, 235, 1, 235, 1, 235, 1, 235, 1, 236, 1, 236, 1, 236, 1, 236, 1, 236, 1, 237, 1, 237, 1, 237, 1, 237, 1, 238, 1, 238, 1, 238, 1, 238, 1, 239, 1, 239, 1, 239, 1, 239, 2, 767, 836, 0, 240, 19, 1, 21, 2, 23, 3, 25, 4, 27, 5, 29, 6, 31, 7, 33, 8, 35, 9, 37, 10, 39, 11, 41, 12, 43, 13, 45, 14, 47, 15, 49, 16, 51, 17, 53, 18, 55, 19, 57, 20, 59, 21, 61, 22, 63, 23, 65, 24, 67, 25, 69, 26, 71, 27, 73, 28, 75, 29, 77, 30, 79, 31, 81, 0, 83, 0, 85, 0, 87, 0, 89, 0, 91, 0, 93, 0, 95, 0, 97, 0, 99, 0, 101, 32, 103, 33, 105, 34, 107, 35, 109, 36, 111, 37, 113, 38, 115, 39, 117, 40, 119, 41, 121, 42, 123, 43, 125, 44, 127, 45, 129, 46, 131, 47, 133, 48, 135, 49, 137, 50, 139, 51, 141, 52, 143, 53, 145, 54, 147, 55, 149, 56, 151, 57, 153, 58, 155, 59, 157, 60, 159, 61, 161, 62, 163, 63, 165, 64, 167, 65, 169, 66, 171, 67, 173, 68, 175, 69, 177, 70, 179, 0, 181, 71, 183, 72, 185, 73, 187, 74, 189, 75, 191, 76, 193, 0, 195, 77, 197, 78, 199, 79, 201, 80, 203, 0, 205, 0, 207, 81, 209, 82, 211, 83, 213, 0, 215, 0, 217, 0, 219, 0, 221, 0, 223, 0, 225, 84, 227, 0, 229, 85, 231, 0, 233, 0, 235, 86, 237, 87, 239, 88, 241, 0, 243, 0, 245, 0, 247, 0, 249, 0, 251, 0, 253, 0, 255, 89, 257, 90, 259, 91, 261, 92, 263, 0, 265, 0, 267, 0, 269, 0, 271, 0, 273, 0, 275, 93, 277, 0, 279, 94, 281, 95, 283, 96, 285, 0, 287, 0, 289, 97, 291, 98, 293, 0, 295, 99, 297, 0, 299, 100, 301, 101, 303, 102, 305, 0, 307, 0, 309, 0, 311, 0, 313, 0, 315, 0, 317, 0, 319, 0, 321, 0, 323, 103, 325, 104, 327, 105, 329, 0, 331, 0, 333, 0, 335, 0, 337, 0, 339, 0, 341, 106, 343, 107, 345, 108, 347, 0, 349, 109, 351, 110, 353, 111, 355, 112, 357, 0, 359, 0, 361, 113, 363, 114, 365, 115, 367, 116, 369, 0, 371, 0, 373, 0, 375, 0, 377, 0, 379, 0, 381, 0, 383, 117, 385, 118, 387, 119, 389, 0, 391, 0, 393, 0, 395, 0, 397, 120, 399, 121, 401, 122, 403, 0, 405, 123, 407, 0, 409, 0, 411, 124, 413, 0, 415, 0, 417, 0, 419, 0, 421, 0, 423, 125, 425, 126, 427, 127, 429, 0, 431, 0, 433, 0, 435, 128, 437, 129, 439, 130, 441, 0, 443, 0, 445, 131, 447, 132, 449, 133, 451, 0, 453, 0, 455, 0, 457, 0, 459, 0, 461, 0, 463, 0, 465, 0, 467, 0, 469, 0, 471, 0, 473, 134, 475, 135, 477, 136, 479, 0, 481, 0, 483, 137, 485, 138, 487, 139, 489, 0, 491, 0, 493, 140, 495, 141, 497, 142, 19, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 36, 2, 0, 68, 68, 100, 100, 2, 0, 73, 73, 105, 105, 2, 0, 83, 83, 115, 115, 2, 0, 69, 69, 101, 101, 2, 0, 67, 67, 99, 99, 2, 0, 84, 84, 116, 116, 2, 0, 82, 82, 114, 114, 2, 0, 79, 79, 111, 111, 2, 0, 80, 80, 112, 112, 2, 0, 78, 78, 110, 110, 2, 0, 72, 72, 104, 104, 2, 0, 86, 86, 118, 118, 2, 0, 65, 65, 97, 97, 2, 0, 76, 76, 108, 108, 2, 0, 88, 88, 120, 120, 2, 0, 70, 70, 102, 102, 2, 0, 77, 77, 109, 109, 2, 0, 71, 71, 103, 103, 2, 0, 75, 75, 107, 107, 2, 0, 87, 87, 119, 119, 2, 0, 85, 85, 117, 117, 6, 0, 9, 10, 13, 13, 32, 32, 47, 47, 91, 91, 93, 93, 2, 0, 10, 10, 13, 13, 3, 0, 9, 10, 13, 13, 32, 32, 1, 0, 48, 57, 2, 0, 65, 90, 97, 122, 8, 0, 34, 34, 78, 78, 82, 82, 84, 84, 92, 92, 110, 110, 114, 114, 116, 116, 4, 0, 10, 10, 13, 13, 34, 34, 92, 92, 2, 0, 43, 43, 45, 45, 1, 0, 96, 96, 2, 0, 66, 66, 98, 98, 2, 0, 89, 89, 121, 121, 11, 0, 9, 10, 13, 13, 32, 32, 34, 34, 44, 44, 47, 47, 58, 58, 61, 61, 91, 91, 93, 93, 124, 124, 2, 0, 42, 42, 47, 47, 11, 0, 9, 10, 13, 13, 32, 32, 34, 35, 44, 44, 47, 47, 58, 58, 60, 60, 62, 63, 92, 92, 124, 124, 2, 0, 74, 74, 106, 106, 1808, 0, 19, 1, 0, 0, 0, 0, 21, 1, 0, 0, 0, 0, 23, 1, 0, 0, 0, 0, 25, 1, 0, 0, 0, 0, 27, 1, 0, 0, 0, 0, 29, 1, 0, 0, 0, 0, 31, 1, 0, 0, 0, 0, 33, 1, 0, 0, 0, 0, 35, 1, 0, 0, 0, 0, 37, 1, 0, 0, 0, 0, 39, 1, 0, 0, 0, 0, 41, 1, 0, 0, 0, 0, 43, 1, 0, 0, 0, 0, 45, 1, 0, 0, 0, 0, 47, 1, 0, 0, 0, 0, 49, 1, 0, 0, 0, 0, 51, 1, 0, 0, 0, 0, 53, 1, 0, 0, 0, 0, 55, 1, 0, 0, 0, 0, 57, 1, 0, 0, 0, 0, 59, 1, 0, 0, 0, 0, 61, 1, 0, 0, 0, 0, 63, 1, 0, 0, 0, 0, 65, 1, 0, 0, 0, 0, 67, 1, 0, 0, 0, 0, 69, 1, 0, 0, 0, 0, 71, 1, 0, 0, 0, 0, 73, 1, 0, 0, 0, 0, 75, 1, 0, 0, 0, 0, 77, 1, 0, 0, 0, 1, 79, 1, 0, 0, 0, 1, 101, 1, 0, 0, 0, 1, 103, 1, 0, 0, 0, 1, 105, 1, 0, 0, 0, 1, 107, 1, 0, 0, 0, 1, 109, 1, 0, 0, 0, 1, 111, 1, 0, 0, 0, 1, 113, 1, 0, 0, 0, 1, 115, 1, 0, 0, 0, 1, 117, 1, 0, 0, 0, 1, 119, 1, 0, 0, 0, 1, 121, 1, 0, 0, 0, 1, 123, 1, 0, 0, 0, 1, 125, 1, 0, 0, 0, 1, 127, 1, 0, 0, 0, 1, 129, 1, 0, 0, 0, 1, 131, 1, 0, 0, 0, 1, 133, 1, 0, 0, 0, 1, 135, 1, 0, 0, 0, 1, 137, 1, 0, 0, 0, 1, 139, 1, 0, 0, 0, 1, 141, 1, 0, 0, 0, 1, 143, 1, 0, 0, 0, 1, 145, 1, 0, 0, 0, 1, 147, 1, 0, 0, 0, 1, 149, 1, 0, 0, 0, 1, 151, 1, 0, 0, 0, 1, 153, 1, 0, 0, 0, 1, 155, 1, 0, 0, 0, 1, 157, 1, 0, 0, 0, 1, 159, 1, 0, 0, 0, 1, 161, 1, 0, 0, 0, 1, 163, 1, 0, 0, 0, 1, 165, 1, 0, 0, 0, 1, 167, 1, 0, 0, 0, 1, 169, 1, 0, 0, 0, 1, 171, 1, 0, 0, 0, 1, 173, 1, 0, 0, 0, 1, 175, 1, 0, 0, 0, 1, 177, 1, 0, 0, 0, 1, 179, 1, 0, 0, 0, 1, 181, 1, 0, 0, 0, 1, 183, 1, 0, 0, 0, 1, 185, 1, 0, 0, 0, 1, 187, 1, 0, 0, 0, 1, 189, 1, 0, 0, 0, 1, 191, 1, 0, 0, 0, 1, 195, 1, 0, 0, 0, 1, 197, 1, 0, 0, 0, 1, 199, 1, 0, 0, 0, 1, 201, 1, 0, 0, 0, 2, 203, 1, 0, 0, 0, 2, 205, 1, 0, 0, 0, 2, 207, 1, 0, 0, 0, 2, 209, 1, 0, 0, 0, 2, 211, 1, 0, 0, 0, 3, 213, 1, 0, 0, 0, 3, 215, 1, 0, 0, 0, 3, 217, 1, 0, 0, 0, 3, 219, 1, 0, 0, 0, 3, 221, 1, 0, 0, 0, 3, 223, 1, 0, 0, 0, 3, 225, 1, 0, 0, 0, 3, 229, 1, 0, 0, 0, 3, 231, 1, 0, 0, 0, 3, 233, 1, 0, 0, 0, 3, 235, 1, 0, 0, 0, 3, 237, 1, 0, 0, 0, 3, 239, 1, 0, 0, 0, 4, 241, 1, 0, 0, 0, 4, 243, 1, 0, 0, 0, 4, 245, 1, 0, 0, 0, 4, 247, 1, 0, 0, 0, 4, 249, 1, 0, 0, 0, 4, 255, 1, 0, 0, 0, 4, 257, 1, 0, 0, 0, 4, 259, 1, 0, 0, 0, 4, 261, 1, 0, 0, 0, 5, 263, 1, 0, 0, 0, 5, 265, 1, 0, 0, 0, 5, 267, 1, 0, 0, 0, 5, 269, 1, 0, 0, 0, 5, 271, 1, 0, 0, 0, 5, 273, 1, 0, 0, 0, 5, 275, 1, 0, 0, 0, 5, 277, 1, 0, 0, 0, 5, 279, 1, 0, 0, 0, 5, 281, 1, 0, 0, 0, 5, 283, 1, 0, 0, 0, 6, 285, 1, 0, 0, 0, 6, 287, 1, 0, 0, 0, 6, 289, 1, 0, 0, 0, 6, 291, 1, 0, 0, 0, 6, 295, 1, 0, 0, 0, 6, 297, 1, 0, 0, 0, 6, 299, 1, 0, 0, 0, 6, 301, 1, 0, 0, 0, 6, 303, 1, 0, 0, 0, 7, 305, 1, 0, 0, 0, 7, 307, 1, 0, 0, 0, 7, 309, 1, 0, 0, 0, 7, 311, 1, 0, 0, 0, 7, 313, 1, 0, 0, 0, 7, 315, 1, 0, 0, 0, 7, 317, 1, 0, 0, 0, 7, 319, 1, 0, 0, 0, 7, 321, 1, 0, 0, 0, 7, 323, 1, 0, 0, 0, 7, 325, 1, 0, 0, 0, 7, 327, 1, 0, 0, 0, 8, 329, 1, 0, 0, 0, 8, 331, 1, 0, 0, 0, 8, 333, 1, 0, 0, 0, 8, 335, 1, 0, 0, 0, 8, 337, 1, 0, 0, 0, 8, 339, 1, 0, 0, 0, 8, 341, 1, 0, 0, 0, 8, 343, 1, 0, 0, 0, 8, 345, 1, 0, 0, 0, 9, 347, 1, 0, 0, 0, 9, 349, 1, 0, 0, 0, 9, 351, 1, 0, 0, 0, 9, 353, 1, 0, 0, 0, 9, 355, 1, 0, 0, 0, 10, 357, 1, 0, 0, 0, 10, 359, 1, 0, 0, 0, 10, 361, 1, 0, 0, 0, 10, 363, 1, 0, 0, 0, 10, 365, 1, 0, 0, 0, 10, 367, 1, 0, 0, 0, 11, 369, 1, 0, 0, 0, 11, 371, 1, 0, 0, 0, 11, 373, 1, 0, 0, 0, 11, 375, 1, 0, 0, 0, 11, 377, 1, 0, 0, 0, 11, 379, 1, 0, 0, 0, 11, 381, 1, 0, 0, 0, 11, 383, 1, 0, 0, 0, 11, 385, 1, 0, 0, 0, 11, 387, 1, 0, 0, 0, 12, 389, 1, 0, 0, 0, 12, 391, 1, 0, 0, 0, 12, 393, 1, 0, 0, 0, 12, 395, 1, 0, 0, 0, 12, 397, 1, 0, 0, 0, 12, 399, 1, 0, 0, 0, 12, 401, 1, 0, 0, 0, 13, 403, 1, 0, 0, 0, 13, 405, 1, 0, 0, 0, 13, 407, 1, 0, 0, 0, 13, 409, 1, 0, 0, 0, 13, 411, 1, 0, 0, 0, 13, 413, 1, 0, 0, 0, 13, 415, 1, 0, 0, 0, 13, 417, 1, 0, 0, 0, 13, 419, 1, 0, 0, 0, 13, 421, 1, 0, 0, 0, 13, 423, 1, 0, 0, 0, 13, 425, 1, 0, 0, 0, 13, 427, 1, 0, 0, 0, 14, 429, 1, 0, 0, 0, 14, 431, 1, 0, 0, 0, 14, 433, 1, 0, 0, 0, 14, 435, 1, 0, 0, 0, 14, 437, 1, 0, 0, 0, 14, 439, 1, 0, 0, 0, 15, 441, 1, 0, 0, 0, 15, 443, 1, 0, 0, 0, 15, 445, 1, 0, 0, 0, 15, 447, 1, 0, 0, 0, 15, 449, 1, 0, 0, 0, 15, 451, 1, 0, 0, 0, 15, 453, 1, 0, 0, 0, 15, 455, 1, 0, 0, 0, 15, 457, 1, 0, 0, 0, 16, 459, 1, 0, 0, 0, 16, 461, 1, 0, 0, 0, 16, 463, 1, 0, 0, 0, 16, 465, 1, 0, 0, 0, 16, 467, 1, 0, 0, 0, 16, 469, 1, 0, 0, 0, 16, 471, 1, 0, 0, 0, 16, 473, 1, 0, 0, 0, 16, 475, 1, 0, 0, 0, 16, 477, 1, 0, 0, 0, 17, 479, 1, 0, 0, 0, 17, 481, 1, 0, 0, 0, 17, 483, 1, 0, 0, 0, 17, 485, 1, 0, 0, 0, 17, 487, 1, 0, 0, 0, 18, 489, 1, 0, 0, 0, 18, 491, 1, 0, 0, 0, 18, 493, 1, 0, 0, 0, 18, 495, 1, 0, 0, 0, 18, 497, 1, 0, 0, 0, 19, 499, 1, 0, 0, 0, 21, 509, 1, 0, 0, 0, 23, 516, 1, 0, 0, 0, 25, 525, 1, 0, 0, 0, 27, 532, 1, 0, 0, 0, 29, 542, 1, 0, 0, 0, 31, 549, 1, 0, 0, 0, 33, 556, 1, 0, 0, 0, 35, 563, 1, 0, 0, 0, 37, 571, 1, 0, 0, 0, 39, 583, 1, 0, 0, 0, 41, 592, 1, 0, 0, 0, 43, 598, 1, 0, 0, 0, 45, 605, 1, 0, 0, 0, 47, 612, 1, 0, 0, 0, 49, 620, 1, 0, 0, 0, 51, 628, 1, 0, 0, 0, 53, 637, 1, 0, 0, 0, 55, 653, 1, 0, 0, 0, 57, 668, 1, 0, 0, 0, 59, 680, 1, 0, 0, 0, 61, 692, 1, 0, 0, 0, 63, 703, 1, 0, 0, 0, 65, 711, 1, 0, 0, 0, 67, 719, 1, 0, 0, 0, 69, 728, 1, 0, 0, 0, 71, 737, 1, 0, 0, 0, 73, 743, 1, 0, 0, 0, 75, 760, 1, 0, 0, 0, 77, 776, 1, 0, 0, 0, 79, 782, 1, 0, 0, 0, 81, 786, 1, 0, 0, 0, 83, 788, 1, 0, 0, 0, 85, 790, 1, 0, 0, 0, 87, 793, 1, 0, 0, 0, 89, 795, 1, 0, 0, 0, 91, 804, 1, 0, 0, 0, 93, 806, 1, 0, 0, 0, 95, 811, 1, 0, 0, 0, 97, 813, 1, 0, 0, 0, 99, 818, 1, 0, 0, 0, 101, 849, 1, 0, 0, 0, 103, 852, 1, 0, 0, 0, 105, 898, 1, 0, 0, 0, 107, 900, 1, 0, 0, 0, 109, 903, 1, 0, 0, 0, 111, 907, 1, 0, 0, 0, 113, 911, 1, 0, 0, 0, 115, 913, 1, 0, 0, 0, 117, 916, 1, 0, 0, 0, 119, 918, 1, 0, 0, 0, 121, 920, 1, 0, 0, 0, 123, 925, 1, 0, 0, 0, 125, 927, 1, 0, 0, 0, 127, 933, 1, 0, 0, 0, 129, 939, 1, 0, 0, 0, 131, 942, 1, 0, 0, 0, 133, 945, 1, 0, 0, 0, 135, 950, 1, 0, 0, 0, 137, 955, 1, 0, 0, 0, 139, 959, 1, 0, 0, 0, 141, 964, 1, 0, 0, 0, 143, 970, 1, 0, 0, 0, 145, 973, 1, 0, 0, 0, 147, 975, 1, 0, 0, 0, 149, 981, 1, 0, 0, 0, 151, 986, 1, 0, 0, 0, 153, 989, 1, 0, 0, 0, 155, 992, 1, 0, 0, 0, 157, 995, 1, 0, 0, 0, 159, 997, 1, 0, 0, 0, 161, 1000, 1, 0, 0, 0, 163, 1002, 1, 0, 0, 0, 165, 1005, 1, 0, 0, 0, 167, 1007, 1, 0, 0, 0, 169, 1009, 1, 0, 0, 0, 171, 1011, 1, 0, 0, 0, 173, 1013, 1, 0, 0, 0, 175, 1015, 1, 0, 0, 0, 177, 1017, 1, 0, 0, 0, 179, 1019, 1, 0, 0, 0, 181, 1040, 1, 0, 0, 0, 183, 1042, 1, 0, 0, 0, 185, 1047, 1, 0, 0, 0, 187, 1052, 1, 0, 0, 0, 189, 1057, 1, 0, 0, 0, 191, 1078, 1, 0, 0, 0, 193, 1080, 1, 0, 0, 0, 195, 1088, 1, 0, 0, 0, 197, 1090, 1, 0, 0, 0, 199, 1094, 1, 0, 0, 0, 201, 1098, 1, 0, 0, 0, 203, 1102, 1, 0, 0, 0, 205, 1107, 1, 0, 0, 0, 207, 1112, 1, 0, 0, 0, 209, 1116, 1, 0, 0, 0, 211, 1120, 1, 0, 0, 0, 213, 1124, 1, 0, 0, 0, 215, 1129, 1, 0, 0, 0, 217, 1133, 1, 0, 0, 0, 219, 1137, 1, 0, 0, 0, 221, 1141, 1, 0, 0, 0, 223, 1145, 1, 0, 0, 0, 225, 1149, 1, 0, 0, 0, 227, 1161, 1, 0, 0, 0, 229, 1164, 1, 0, 0, 0, 231, 1168, 1, 0, 0, 0, 233, 1172, 1, 0, 0, 0, 235, 1176, 1, 0, 0, 0, 237, 1180, 1, 0, 0, 0, 239, 1184, 1, 0, 0, 0, 241, 1188, 1, 0, 0, 0, 243, 1193, 1, 0, 0, 0, 245, 1197, 1, 0, 0, 0, 247, 1201, 1, 0, 0, 0, 249, 1205, 1, 0, 0, 0, 251, 1213, 1, 0, 0, 0, 253, 1234, 1, 0, 0, 0, 255, 1238, 1, 0, 0, 0, 257, 1242, 1, 0, 0, 0, 259, 1246, 1, 0, 0, 0, 261, 1250, 1, 0, 0, 0, 263, 1254, 1, 0, 0, 0, 265, 1259, 1, 0, 0, 0, 267, 1263, 1, 0, 0, 0, 269, 1267, 1, 0, 0, 0, 271, 1271, 1, 0, 0, 0, 273, 1275, 1, 0, 0, 0, 275, 1279, 1, 0, 0, 0, 277, 1282, 1, 0, 0, 0, 279, 1286, 1, 0, 0, 0, 281, 1290, 1, 0, 0, 0, 283, 1294, 1, 0, 0, 0, 285, 1298, 1, 0, 0, 0, 287, 1303, 1, 0, 0, 0, 289, 1308, 1, 0, 0, 0, 291, 1313, 1, 0, 0, 0, 293, 1320, 1, 0, 0, 0, 295, 1329, 1, 0, 0, 0, 297, 1336, 1, 0, 0, 0, 299, 1340, 1, 0, 0, 0, 301, 1344, 1, 0, 0, 0, 303, 1348, 1, 0, 0, 0, 305, 1352, 1, 0, 0, 0, 307, 1358, 1, 0, 0, 0, 309, 1362, 1, 0, 0, 0, 311, 1366, 1, 0, 0, 0, 313, 1370, 1, 0, 0, 0, 315, 1374, 1, 0, 0, 0, 317, 1378, 1, 0, 0, 0, 319, 1382, 1, 0, 0, 0, 321, 1386, 1, 0, 0, 0, 323, 1390, 1, 0, 0, 0, 325, 1394, 1, 0, 0, 0, 327, 1398, 1, 0, 0, 0, 329, 1402, 1, 0, 0, 0, 331, 1407, 1, 0, 0, 0, 333, 1411, 1, 0, 0, 0, 335, 1415, 1, 0, 0, 0, 337, 1419, 1, 0, 0, 0, 339, 1423, 1, 0, 0, 0, 341, 1427, 1, 0, 0, 0, 343, 1431, 1, 0, 0, 0, 345, 1435, 1, 0, 0, 0, 347, 1439, 1, 0, 0, 0, 349, 1444, 1, 0, 0, 0, 351, 1449, 1, 0, 0, 0, 353, 1453, 1, 0, 0, 0, 355, 1457, 1, 0, 0, 0, 357, 1461, 1, 0, 0, 0, 359, 1466, 1, 0, 0, 0, 361, 1475, 1, 0, 0, 0, 363, 1479, 1, 0, 0, 0, 365, 1483, 1, 0, 0, 0, 367, 1487, 1, 0, 0, 0, 369, 1491, 1, 0, 0, 0, 371, 1496, 1, 0, 0, 0, 373, 1500, 1, 0, 0, 0, 375, 1504, 1, 0, 0, 0, 377, 1508, 1, 0, 0, 0, 379, 1513, 1, 0, 0, 0, 381, 1517, 1, 0, 0, 0, 383, 1521, 1, 0, 0, 0, 385, 1525, 1, 0, 0, 0, 387, 1529, 1, 0, 0, 0, 389, 1533, 1, 0, 0, 0, 391, 1539, 1, 0, 0, 0, 393, 1543, 1, 0, 0, 0, 395, 1547, 1, 0, 0, 0, 397, 1551, 1, 0, 0, 0, 399, 1555, 1, 0, 0, 0, 401, 1559, 1, 0, 0, 0, 403, 1563, 1, 0, 0, 0, 405, 1568, 1, 0, 0, 0, 407, 1573, 1, 0, 0, 0, 409, 1577, 1, 0, 0, 0, 411, 1583, 1, 0, 0, 0, 413, 1592, 1, 0, 0, 0, 415, 1596, 1, 0, 0, 0, 417, 1600, 1, 0, 0, 0, 419, 1604, 1, 0, 0, 0, 421, 1608, 1, 0, 0, 0, 423, 1612, 1, 0, 0, 0, 425, 1616, 1, 0, 0, 0, 427, 1620, 1, 0, 0, 0, 429, 1624, 1, 0, 0, 0, 431, 1629, 1, 0, 0, 0, 433, 1635, 1, 0, 0, 0, 435, 1641, 1, 0, 0, 0, 437, 1645, 1, 0, 0, 0, 439, 1649, 1, 0, 0, 0, 441, 1653, 1, 0, 0, 0, 443, 1659, 1, 0, 0, 0, 445, 1665, 1, 0, 0, 0, 447, 1669, 1, 0, 0, 0, 449, 1673, 1, 0, 0, 0, 451, 1677, 1, 0, 0, 0, 453, 1683, 1, 0, 0, 0, 455, 1689, 1, 0, 0, 0, 457, 1695, 1, 0, 0, 0, 459, 1700, 1, 0, 0, 0, 461, 1705, 1, 0, 0, 0, 463, 1709, 1, 0, 0, 0, 465, 1713, 1, 0, 0, 0, 467, 1717, 1, 0, 0, 0, 469, 1721, 1, 0, 0, 0, 471, 1725, 1, 0, 0, 0, 473, 1729, 1, 0, 0, 0, 475, 1733, 1, 0, 0, 0, 477, 1737, 1, 0, 0, 0, 479, 1741, 1, 0, 0, 0, 481, 1746, 1, 0, 0, 0, 483, 1750, 1, 0, 0, 0, 485, 1754, 1, 0, 0, 0, 487, 1758, 1, 0, 0, 0, 489, 1762, 1, 0, 0, 0, 491, 1767, 1, 0, 0, 0, 493, 1772, 1, 0, 0, 0, 495, 1776, 1, 0, 0, 0, 497, 1780, 1, 0, 0, 0, 499, 500, 7, 0, 0, 0, 500, 501, 7, 1, 0, 0, 501, 502, 7, 2, 0, 0, 502, 503, 7, 2, 0, 0, 503, 504, 7, 3, 0, 0, 504, 505, 7, 4, 0, 0, 505, 506, 7, 5, 0, 0, 506, 507, 1, 0, 0, 0, 507, 508, 6, 0, 0, 0, 508, 20, 1, 0, 0, 0, 509, 510, 7, 0, 0, 0, 510, 511, 7, 6, 0, 0, 511, 512, 7, 7, 0, 0, 512, 513, 7, 8, 0, 0, 513, 514, 1, 0, 0, 0, 514, 515, 6, 1, 1, 0, 515, 22, 1, 0, 0, 0, 516, 517, 7, 3, 0, 0, 517, 518, 7, 9, 0, 0, 518, 519, 7, 6, 0, 0, 519, 520, 7, 1, 0, 0, 520, 521, 7, 4, 0, 0, 521, 522, 7, 10, 0, 0, 522, 523, 1, 0, 0, 0, 523, 524, 6, 2, 2, 0, 524, 24, 1, 0, 0, 0, 525, 526, 7, 3, 0, 0, 526, 527, 7, 11, 0, 0, 527, 528, 7, 12, 0, 0, 528, 529, 7, 13, 0, 0, 529, 530, 1, 0, 0, 0, 530, 531, 6, 3, 0, 0, 531, 26, 1, 0, 0, 0, 532, 533, 7, 3, 0, 0, 533, 534, 7, 14, 0, 0, 534, 535, 7, 8, 0, 0, 535, 536, 7, 13, 0, 0, 536, 537, 7, 12, 0, 0, 537, 538, 7, 1, 0, 0, 538, 539, 7, 9, 0, 0, 539, 540, 1, 0, 0, 0, 540, 541, 6, 4, 3, 0, 541, 28, 1, 0, 0, 0, 542, 543, 7, 15, 0, 0, 543, 544, 7, 6, 0, 0, 544, 545, 7, 7, 0, 0, 545, 546, 7, 16, 0, 0, 546, 547, 1, 0, 0, 0, 547, 548, 6, 5, 4, 0, 548, 30, 1, 0, 0, 0, 549, 550, 7, 17, 0, 0, 550, 551, 7, 6, 0, 0, 551, 552, 7, 7, 0, 0, 552, 553, 7, 18, 0, 0, 553, 554, 1, 0, 0, 0, 554, 555, 6, 6, 0, 0, 555, 32, 1, 0, 0, 0, 556, 557, 7, 18, 0, 0, 557, 558, 7, 3, 0, 0, 558, 559, 7, 3, 0, 0, 559, 560, 7, 8, 0, 0, 560, 561, 1, 0, 0, 0, 561, 562, 6, 7, 1, 0, 562, 34, 1, 0, 0, 0, 563, 564, 7, 13, 0, 0, 564, 565, 7, 1, 0, 0, 565, 566, 7, 16, 0, 0, 566, 567, 7, 1, 0, 0, 567, 568, 7, 5, 0, 0, 568, 569, 1, 0, 0, 0, 569, 570, 6, 8, 0, 0, 570, 36, 1, 0, 0, 0, 571, 572, 7, 16, 0, 0, 572, 573, 7, 11, 0, 0, 573, 574, 5, 95, 0, 0, 574, 575, 7, 3, 0, 0, 575, 576, 7, 14, 0, 0, 576, 577, 7, 8, 0, 0, 577, 578, 7, 12, 0, 0, 578, 579, 7, 9, 0, 0, 579, 580, 7, 0, 0, 0, 580, 581, 1, 0, 0, 0, 581, 582, 6, 9, 5, 0, 582, 38, 1, 0, 0, 0, 583, 584, 7, 6, 0, 0, 584, 585, 7, 3, 0, 0, 585, 586, 7, 9, 0, 0, 586, 587, 7, 12, 0, 0, 587, 588, 7, 16, 0, 0, 588, 589, 7, 3, 0, 0, 589, 590, 1, 0, 0, 0, 590, 591, 6, 10, 6, 0, 591, 40, 1, 0, 0, 0, 592, 593, 7, 6, 0, 0, 593, 594, 7, 7, 0, 0, 594, 595, 7, 19, 0, 0, 595, 596, 1, 0, 0, 0, 596, 597, 6, 11, 0, 0, 597, 42, 1, 0, 0, 0, 598, 599, 7, 2, 0, 0, 599, 600, 7, 10, 0, 0, 600, 601, 7, 7, 0, 0, 601, 602, 7, 19, 0, 0, 602, 603, 1, 0, 0, 0, 603, 604, 6, 12, 7, 0, 604, 44, 1, 0, 0, 0, 605, 606, 7, 2, 0, 0, 606, 607, 7, 7, 0, 0, 607, 608, 7, 6, 0, 0, 608, 609, 7, 5, 0, 0, 609, 610, 1, 0, 0, 0, 610, 611, 6, 13, 0, 0, 611, 46, 1, 0, 0, 0, 612, 613, 7, 2, 0, 0, 613, 614, 7, 5, 0, 0, 614, 615, 7, 12, 0, 0, 615, 616, 7, 5, 0, 0, 616, 617, 7, 2, 0, 0, 617, 618, 1, 0, 0, 0, 618, 619, 6, 14, 0, 0, 619, 48, 1, 0, 0, 0, 620, 621, 7, 19, 0, 0, 621, 622, 7, 10, 0, 0, 622, 623, 7, 3, 0, 0, 623, 624, 7, 6, 0, 0, 624, 625, 7, 3, 0, 0, 625, 626, 1, 0, 0, 0, 626, 627, 6, 15, 0, 0, 627, 50, 1, 0, 0, 0, 628, 629, 7, 13, 0, 0, 629, 630, 7, 7, 0, 0, 630, 631, 7, 7, 0, 0, 631, 632, 7, 18, 0, 0, 632, 633, 7, 20, 0, 0, 633, 634, 7, 8, 0, 0, 634, 635, 1, 0, 0, 0, 635, 636, 6, 16, 8, 0, 636, 52, 1, 0, 0, 0, 637, 638, 4, 17, 0, 0, 638, 639, 7, 4, 0, 0, 639, 640, 7, 10, 0, 0, 640, 641, 7, 12, 0, 0, 641, 642, 7, 9, 0, 0, 642, 643, 7, 17, 0, 0, 643, 644, 7, 3, 0, 0, 644, 645, 5, 95, 0, 0, 645, 646, 7, 8, 0, 0, 646, 647, 7, 7, 0, 0, 647, 648, 7, 1, 0, 0, 648, 649, 7, 9, 0, 0, 649, 650, 7, 5, 0, 0, 650, 651, 1, 0, 0, 0, 651, 652, 6, 17, 9, 0, 652, 54, 1, 0, 0, 0, 653, 654, 4, 18, 1, 0, 654, 655, 7, 1, 0, 0, 655, 656, 7, 9, 0, 0, 656, 657, 7, 13, 0, 0, 657, 658, 7, 1, 0, 0, 658, 659, 7, 9, 0, 0, 659, 660, 7, 3, 0, 0, 660, 661, 7, 2, 0, 0, 661, 662, 7, 5, 0, 0, 662, 663, 7, 12, 0, 0, 663, 664, 7, 5, 0, 0, 664, 665, 7, 2, 0, 0, 665, 666, 1, 0, 0, 0, 666, 667, 6, 18, 0, 0, 667, 56, 1, 0, 0, 0, 668, 669, 4, 19, 2, 0, 669, 670, 7, 1, 0, 0, 670, 671, 7, 9, 0, 0, 671, 672, 7, 2, 0, 0, 672, 673, 7, 1, 0, 0, 673, 674, 7, 2, 0, 0, 674, 675, 7, 5, 0, 0, 675, 676, 5, 95, 0, 0, 676, 677, 5, 128020, 0, 0, 677, 678, 1, 0, 0, 0, 678, 679, 6, 19, 1, 0, 679, 58, 1, 0, 0, 0, 680, 681, 4, 20, 3, 0, 681, 682, 7, 13, 0, 0, 682, 683, 7, 7, 0, 0, 683, 684, 7, 7, 0, 0, 684, 685, 7, 18, 0, 0, 685, 686, 7, 20, 0, 0, 686, 687, 7, 8, 0, 0, 687, 688, 5, 95, 0, 0, 688, 689, 5, 128020, 0, 0, 689, 690, 1, 0, 0, 0, 690, 691, 6, 20, 10, 0, 691, 60, 1, 0, 0, 0, 692, 693, 4, 21, 4, 0, 693, 694, 7, 16, 0, 0, 694, 695, 7, 3, 0, 0, 695, 696, 7, 5, 0, 0, 696, 697, 7, 6, 0, 0, 697, 698, 7, 1, 0, 0, 698, 699, 7, 4, 0, 0, 699, 700, 7, 2, 0, 0, 700, 701, 1, 0, 0, 0, 701, 702, 6, 21, 11, 0, 702, 62, 1, 0, 0, 0, 703, 704, 4, 22, 5, 0, 704, 705, 7, 15, 0, 0, 705, 706, 7, 20, 0, 0, 706, 707, 7, 13, 0, 0, 707, 708, 7, 13, 0, 0, 708, 709, 1, 0, 0, 0, 709, 710, 6, 22, 8, 0, 710, 64, 1, 0, 0, 0, 711, 712, 4, 23, 6, 0, 712, 713, 7, 13, 0, 0, 713, 714, 7, 3, 0, 0, 714, 715, 7, 15, 0, 0, 715, 716, 7, 5, 0, 0, 716, 717, 1, 0, 0, 0, 717, 718, 6, 23, 8, 0, 718, 66, 1, 0, 0, 0, 719, 720, 4, 24, 7, 0, 720, 721, 7, 6, 0, 0, 721, 722, 7, 1, 0, 0, 722, 723, 7, 17, 0, 0, 723, 724, 7, 10, 0, 0, 724, 725, 7, 5, 0, 0, 725, 726, 1, 0, 0, 0, 726, 727, 6, 24, 8, 0, 727, 68, 1, 0, 0, 0, 728, 729, 4, 25, 8, 0, 729, 730, 7, 15, 0, 0, 730, 731, 7, 7, 0, 0, 731, 732, 7, 6, 0, 0, 732, 733, 7, 18, 0, 0, 733, 734, 1, 0, 0, 0, 734, 735, 6, 25, 12, 0, 735, 70, 1, 0, 0, 0, 736, 738, 8, 21, 0, 0, 737, 736, 1, 0, 0, 0, 738, 739, 1, 0, 0, 0, 739, 737, 1, 0, 0, 0, 739, 740, 1, 0, 0, 0, 740, 741, 1, 0, 0, 0, 741, 742, 6, 26, 0, 0, 742, 72, 1, 0, 0, 0, 743, 744, 5, 47, 0, 0, 744, 745, 5, 47, 0, 0, 745, 749, 1, 0, 0, 0, 746, 748, 8, 22, 0, 0, 747, 746, 1, 0, 0, 0, 748, 751, 1, 0, 0, 0, 749, 747, 1, 0, 0, 0, 749, 750, 1, 0, 0, 0, 750, 753, 1, 0, 0, 0, 751, 749, 1, 0, 0, 0, 752, 754, 5, 13, 0, 0, 753, 752, 1, 0, 0, 0, 753, 754, 1, 0, 0, 0, 754, 756, 1, 0, 0, 0, 755, 757, 5, 10, 0, 0, 756, 755, 1, 0, 0, 0, 756, 757, 1, 0, 0, 0, 757, 758, 1, 0, 0, 0, 758, 759, 6, 27, 13, 0, 759, 74, 1, 0, 0, 0, 760, 761, 5, 47, 0, 0, 761, 762, 5, 42, 0, 0, 762, 767, 1, 0, 0, 0, 763, 766, 3, 75, 28, 0, 764, 766, 9, 0, 0, 0, 765, 763, 1, 0, 0, 0, 765, 764, 1, 0, 0, 0, 766, 769, 1, 0, 0, 0, 767, 768, 1, 0, 0, 0, 767, 765, 1, 0, 0, 0, 768, 770, 1, 0, 0, 0, 769, 767, 1, 0, 0, 0, 770, 771, 5, 42, 0, 0, 771, 772, 5, 47, 0, 0, 772, 773, 1, 0, 0, 0, 773, 774, 6, 28, 13, 0, 774, 76, 1, 0, 0, 0, 775, 777, 7, 23, 0, 0, 776, 775, 1, 0, 0, 0, 777, 778, 1, 0, 0, 0, 778, 776, 1, 0, 0, 0, 778, 779, 1, 0, 0, 0, 779, 780, 1, 0, 0, 0, 780, 781, 6, 29, 13, 0, 781, 78, 1, 0, 0, 0, 782, 783, 5, 124, 0, 0, 783, 784, 1, 0, 0, 0, 784, 785, 6, 30, 14, 0, 785, 80, 1, 0, 0, 0, 786, 787, 7, 24, 0, 0, 787, 82, 1, 0, 0, 0, 788, 789, 7, 25, 0, 0, 789, 84, 1, 0, 0, 0, 790, 791, 5, 92, 0, 0, 791, 792, 7, 26, 0, 0, 792, 86, 1, 0, 0, 0, 793, 794, 8, 27, 0, 0, 794, 88, 1, 0, 0, 0, 795, 797, 7, 3, 0, 0, 796, 798, 7, 28, 0, 0, 797, 796, 1, 0, 0, 0, 797, 798, 1, 0, 0, 0, 798, 800, 1, 0, 0, 0, 799, 801, 3, 81, 31, 0, 800, 799, 1, 0, 0, 0, 801, 802, 1, 0, 0, 0, 802, 800, 1, 0, 0, 0, 802, 803, 1, 0, 0, 0, 803, 90, 1, 0, 0, 0, 804, 805, 5, 64, 0, 0, 805, 92, 1, 0, 0, 0, 806, 807, 5, 96, 0, 0, 807, 94, 1, 0, 0, 0, 808, 812, 8, 29, 0, 0, 809, 810, 5, 96, 0, 0, 810, 812, 5, 96, 0, 0, 811, 808, 1, 0, 0, 0, 811, 809, 1, 0, 0, 0, 812, 96, 1, 0, 0, 0, 813, 814, 5, 95, 0, 0, 814, 98, 1, 0, 0, 0, 815, 819, 3, 83, 32, 0, 816, 819, 3, 81, 31, 0, 817, 819, 3, 97, 39, 0, 818, 815, 1, 0, 0, 0, 818, 816, 1, 0, 0, 0, 818, 817, 1, 0, 0, 0, 819, 100, 1, 0, 0, 0, 820, 825, 5, 34, 0, 0, 821, 824, 3, 85, 33, 0, 822, 824, 3, 87, 34, 0, 823, 821, 1, 0, 0, 0, 823, 822, 1, 0, 0, 0, 824, 827, 1, 0, 0, 0, 825, 823, 1, 0, 0, 0, 825, 826, 1, 0, 0, 0, 826, 828, 1, 0, 0, 0, 827, 825, 1, 0, 0, 0, 828, 850, 5, 34, 0, 0, 829, 830, 5, 34, 0, 0, 830, 831, 5, 34, 0, 0, 831, 832, 5, 34, 0, 0, 832, 836, 1, 0, 0, 0, 833, 835, 8, 22, 0, 0, 834, 833, 1, 0, 0, 0, 835, 838, 1, 0, 0, 0, 836, 837, 1, 0, 0, 0, 836, 834, 1, 0, 0, 0, 837, 839, 1, 0, 0, 0, 838, 836, 1, 0, 0, 0, 839, 840, 5, 34, 0, 0, 840, 841, 5, 34, 0, 0, 841, 842, 5, 34, 0, 0, 842, 844, 1, 0, 0, 0, 843, 845, 5, 34, 0, 0, 844, 843, 1, 0, 0, 0, 844, 845, 1, 0, 0, 0, 845, 847, 1, 0, 0, 0, 846, 848, 5, 34, 0, 0, 847, 846, 1, 0, 0, 0, 847, 848, 1, 0, 0, 0, 848, 850, 1, 0, 0, 0, 849, 820, 1, 0, 0, 0, 849, 829, 1, 0, 0, 0, 850, 102, 1, 0, 0, 0, 851, 853, 3, 81, 31, 0, 852, 851, 1, 0, 0, 0, 853, 854, 1, 0, 0, 0, 854, 852, 1, 0, 0, 0, 854, 855, 1, 0, 0, 0, 855, 104, 1, 0, 0, 0, 856, 858, 3, 81, 31, 0, 857, 856, 1, 0, 0, 0, 858, 859, 1, 0, 0, 0, 859, 857, 1, 0, 0, 0, 859, 860, 1, 0, 0, 0, 860, 861, 1, 0, 0, 0, 861, 865, 3, 123, 52, 0, 862, 864, 3, 81, 31, 0, 863, 862, 1, 0, 0, 0, 864, 867, 1, 0, 0, 0, 865, 863, 1, 0, 0, 0, 865, 866, 1, 0, 0, 0, 866, 899, 1, 0, 0, 0, 867, 865, 1, 0, 0, 0, 868, 870, 3, 123, 52, 0, 869, 871, 3, 81, 31, 0, 870, 869, 1, 0, 0, 0, 871, 872, 1, 0, 0, 0, 872, 870, 1, 0, 0, 0, 872, 873, 1, 0, 0, 0, 873, 899, 1, 0, 0, 0, 874, 876, 3, 81, 31, 0, 875, 874, 1, 0, 0, 0, 876, 877, 1, 0, 0, 0, 877, 875, 1, 0, 0, 0, 877, 878, 1, 0, 0, 0, 878, 886, 1, 0, 0, 0, 879, 883, 3, 123, 52, 0, 880, 882, 3, 81, 31, 0, 881, 880, 1, 0, 0, 0, 882, 885, 1, 0, 0, 0, 883, 881, 1, 0, 0, 0, 883, 884, 1, 0, 0, 0, 884, 887, 1, 0, 0, 0, 885, 883, 1, 0, 0, 0, 886, 879, 1, 0, 0, 0, 886, 887, 1, 0, 0, 0, 887, 888, 1, 0, 0, 0, 888, 889, 3, 89, 35, 0, 889, 899, 1, 0, 0, 0, 890, 892, 3, 123, 52, 0, 891, 893, 3, 81, 31, 0, 892, 891, 1, 0, 0, 0, 893, 894, 1, 0, 0, 0, 894, 892, 1, 0, 0, 0, 894, 895, 1, 0, 0, 0, 895, 896, 1, 0, 0, 0, 896, 897, 3, 89, 35, 0, 897, 899, 1, 0, 0, 0, 898, 857, 1, 0, 0, 0, 898, 868, 1, 0, 0, 0, 898, 875, 1, 0, 0, 0, 898, 890, 1, 0, 0, 0, 899, 106, 1, 0, 0, 0, 900, 901, 7, 30, 0, 0, 901, 902, 7, 31, 0, 0, 902, 108, 1, 0, 0, 0, 903, 904, 7, 12, 0, 0, 904, 905, 7, 9, 0, 0, 905, 906, 7, 0, 0, 0, 906, 110, 1, 0, 0, 0, 907, 908, 7, 12, 0, 0, 908, 909, 7, 2, 0, 0, 909, 910, 7, 4, 0, 0, 910, 112, 1, 0, 0, 0, 911, 912, 5, 61, 0, 0, 912, 114, 1, 0, 0, 0, 913, 914, 5, 58, 0, 0, 914, 915, 5, 58, 0, 0, 915, 116, 1, 0, 0, 0, 916, 917, 5, 58, 0, 0, 917, 118, 1, 0, 0, 0, 918, 919, 5, 44, 0, 0, 919, 120, 1, 0, 0, 0, 920, 921, 7, 0, 0, 0, 921, 922, 7, 3, 0, 0, 922, 923, 7, 2, 0, 0, 923, 924, 7, 4, 0, 0, 924, 122, 1, 0, 0, 0, 925, 926, 5, 46, 0, 0, 926, 124, 1, 0, 0, 0, 927, 928, 7, 15, 0, 0, 928, 929, 7, 12, 0, 0, 929, 930, 7, 13, 0, 0, 930, 931, 7, 2, 0, 0, 931, 932, 7, 3, 0, 0, 932, 126, 1, 0, 0, 0, 933, 934, 7, 15, 0, 0, 934, 935, 7, 1, 0, 0, 935, 936, 7, 6, 0, 0, 936, 937, 7, 2, 0, 0, 937, 938, 7, 5, 0, 0, 938, 128, 1, 0, 0, 0, 939, 940, 7, 1, 0, 0, 940, 941, 7, 9, 0, 0, 941, 130, 1, 0, 0, 0, 942, 943, 7, 1, 0, 0, 943, 944, 7, 2, 0, 0, 944, 132, 1, 0, 0, 0, 945, 946, 7, 13, 0, 0, 946, 947, 7, 12, 0, 0, 947, 948, 7, 2, 0, 0, 948, 949, 7, 5, 0, 0, 949, 134, 1, 0, 0, 0, 950, 951, 7, 13, 0, 0, 951, 952, 7, 1, 0, 0, 952, 953, 7, 18, 0, 0, 953, 954, 7, 3, 0, 0, 954, 136, 1, 0, 0, 0, 955, 956, 7, 9, 0, 0, 956, 957, 7, 7, 0, 0, 957, 958, 7, 5, 0, 0, 958, 138, 1, 0, 0, 0, 959, 960, 7, 9, 0, 0, 960, 961, 7, 20, 0, 0, 961, 962, 7, 13, 0, 0, 962, 963, 7, 13, 0, 0, 963, 140, 1, 0, 0, 0, 964, 965, 7, 9, 0, 0, 965, 966, 7, 20, 0, 0, 966, 967, 7, 13, 0, 0, 967, 968, 7, 13, 0, 0, 968, 969, 7, 2, 0, 0, 969, 142, 1, 0, 0, 0, 970, 971, 7, 7, 0, 0, 971, 972, 7, 6, 0, 0, 972, 144, 1, 0, 0, 0, 973, 974, 5, 63, 0, 0, 974, 146, 1, 0, 0, 0, 975, 976, 7, 6, 0, 0, 976, 977, 7, 13, 0, 0, 977, 978, 7, 1, 0, 0, 978, 979, 7, 18, 0, 0, 979, 980, 7, 3, 0, 0, 980, 148, 1, 0, 0, 0, 981, 982, 7, 5, 0, 0, 982, 983, 7, 6, 0, 0, 983, 984, 7, 20, 0, 0, 984, 985, 7, 3, 0, 0, 985, 150, 1, 0, 0, 0, 986, 987, 5, 61, 0, 0, 987, 988, 5, 61, 0, 0, 988, 152, 1, 0, 0, 0, 989, 990, 5, 61, 0, 0, 990, 991, 5, 126, 0, 0, 991, 154, 1, 0, 0, 0, 992, 993, 5, 33, 0, 0, 993, 994, 5, 61, 0, 0, 994, 156, 1, 0, 0, 0, 995, 996, 5, 60, 0, 0, 996, 158, 1, 0, 0, 0, 997, 998, 5, 60, 0, 0, 998, 999, 5, 61, 0, 0, 999, 160, 1, 0, 0, 0, 1000, 1001, 5, 62, 0, 0, 1001, 162, 1, 0, 0, 0, 1002, 1003, 5, 62, 0, 0, 1003, 1004, 5, 61, 0, 0, 1004, 164, 1, 0, 0, 0, 1005, 1006, 5, 43, 0, 0, 1006, 166, 1, 0, 0, 0, 1007, 1008, 5, 45, 0, 0, 1008, 168, 1, 0, 0, 0, 1009, 1010, 5, 42, 0, 0, 1010, 170, 1, 0, 0, 0, 1011, 1012, 5, 47, 0, 0, 1012, 172, 1, 0, 0, 0, 1013, 1014, 5, 37, 0, 0, 1014, 174, 1, 0, 0, 0, 1015, 1016, 5, 123, 0, 0, 1016, 176, 1, 0, 0, 0, 1017, 1018, 5, 125, 0, 0, 1018, 178, 1, 0, 0, 0, 1019, 1020, 3, 49, 15, 0, 1020, 1021, 1, 0, 0, 0, 1021, 1022, 6, 80, 15, 0, 1022, 180, 1, 0, 0, 0, 1023, 1026, 3, 145, 63, 0, 1024, 1027, 3, 83, 32, 0, 1025, 1027, 3, 97, 39, 0, 1026, 1024, 1, 0, 0, 0, 1026, 1025, 1, 0, 0, 0, 1027, 1031, 1, 0, 0, 0, 1028, 1030, 3, 99, 40, 0, 1029, 1028, 1, 0, 0, 0, 1030, 1033, 1, 0, 0, 0, 1031, 1029, 1, 0, 0, 0, 1031, 1032, 1, 0, 0, 0, 1032, 1041, 1, 0, 0, 0, 1033, 1031, 1, 0, 0, 0, 1034, 1036, 3, 145, 63, 0, 1035, 1037, 3, 81, 31, 0, 1036, 1035, 1, 0, 0, 0, 1037, 1038, 1, 0, 0, 0, 1038, 1036, 1, 0, 0, 0, 1038, 1039, 1, 0, 0, 0, 1039, 1041, 1, 0, 0, 0, 1040, 1023, 1, 0, 0, 0, 1040, 1034, 1, 0, 0, 0, 1041, 182, 1, 0, 0, 0, 1042, 1043, 5, 91, 0, 0, 1043, 1044, 1, 0, 0, 0, 1044, 1045, 6, 82, 0, 0, 1045, 1046, 6, 82, 0, 0, 1046, 184, 1, 0, 0, 0, 1047, 1048, 5, 93, 0, 0, 1048, 1049, 1, 0, 0, 0, 1049, 1050, 6, 83, 14, 0, 1050, 1051, 6, 83, 14, 0, 1051, 186, 1, 0, 0, 0, 1052, 1053, 5, 40, 0, 0, 1053, 1054, 1, 0, 0, 0, 1054, 1055, 6, 84, 0, 0, 1055, 1056, 6, 84, 0, 0, 1056, 188, 1, 0, 0, 0, 1057, 1058, 5, 41, 0, 0, 1058, 1059, 1, 0, 0, 0, 1059, 1060, 6, 85, 14, 0, 1060, 1061, 6, 85, 14, 0, 1061, 190, 1, 0, 0, 0, 1062, 1066, 3, 83, 32, 0, 1063, 1065, 3, 99, 40, 0, 1064, 1063, 1, 0, 0, 0, 1065, 1068, 1, 0, 0, 0, 1066, 1064, 1, 0, 0, 0, 1066, 1067, 1, 0, 0, 0, 1067, 1079, 1, 0, 0, 0, 1068, 1066, 1, 0, 0, 0, 1069, 1072, 3, 97, 39, 0, 1070, 1072, 3, 91, 36, 0, 1071, 1069, 1, 0, 0, 0, 1071, 1070, 1, 0, 0, 0, 1072, 1074, 1, 0, 0, 0, 1073, 1075, 3, 99, 40, 0, 1074, 1073, 1, 0, 0, 0, 1075, 1076, 1, 0, 0, 0, 1076, 1074, 1, 0, 0, 0, 1076, 1077, 1, 0, 0, 0, 1077, 1079, 1, 0, 0, 0, 1078, 1062, 1, 0, 0, 0, 1078, 1071, 1, 0, 0, 0, 1079, 192, 1, 0, 0, 0, 1080, 1082, 3, 93, 37, 0, 1081, 1083, 3, 95, 38, 0, 1082, 1081, 1, 0, 0, 0, 1083, 1084, 1, 0, 0, 0, 1084, 1082, 1, 0, 0, 0, 1084, 1085, 1, 0, 0, 0, 1085, 1086, 1, 0, 0, 0, 1086, 1087, 3, 93, 37, 0, 1087, 194, 1, 0, 0, 0, 1088, 1089, 3, 193, 87, 0, 1089, 196, 1, 0, 0, 0, 1090, 1091, 3, 73, 27, 0, 1091, 1092, 1, 0, 0, 0, 1092, 1093, 6, 89, 13, 0, 1093, 198, 1, 0, 0, 0, 1094, 1095, 3, 75, 28, 0, 1095, 1096, 1, 0, 0, 0, 1096, 1097, 6, 90, 13, 0, 1097, 200, 1, 0, 0, 0, 1098, 1099, 3, 77, 29, 0, 1099, 1100, 1, 0, 0, 0, 1100, 1101, 6, 91, 13, 0, 1101, 202, 1, 0, 0, 0, 1102, 1103, 3, 183, 82, 0, 1103, 1104, 1, 0, 0, 0, 1104, 1105, 6, 92, 16, 0, 1105, 1106, 6, 92, 17, 0, 1106, 204, 1, 0, 0, 0, 1107, 1108, 3, 79, 30, 0, 1108, 1109, 1, 0, 0, 0, 1109, 1110, 6, 93, 18, 0, 1110, 1111, 6, 93, 14, 0, 1111, 206, 1, 0, 0, 0, 1112, 1113, 3, 77, 29, 0, 1113, 1114, 1, 0, 0, 0, 1114, 1115, 6, 94, 13, 0, 1115, 208, 1, 0, 0, 0, 1116, 1117, 3, 73, 27, 0, 1117, 1118, 1, 0, 0, 0, 1118, 1119, 6, 95, 13, 0, 1119, 210, 1, 0, 0, 0, 1120, 1121, 3, 75, 28, 0, 1121, 1122, 1, 0, 0, 0, 1122, 1123, 6, 96, 13, 0, 1123, 212, 1, 0, 0, 0, 1124, 1125, 3, 79, 30, 0, 1125, 1126, 1, 0, 0, 0, 1126, 1127, 6, 97, 18, 0, 1127, 1128, 6, 97, 14, 0, 1128, 214, 1, 0, 0, 0, 1129, 1130, 3, 183, 82, 0, 1130, 1131, 1, 0, 0, 0, 1131, 1132, 6, 98, 16, 0, 1132, 216, 1, 0, 0, 0, 1133, 1134, 3, 185, 83, 0, 1134, 1135, 1, 0, 0, 0, 1135, 1136, 6, 99, 19, 0, 1136, 218, 1, 0, 0, 0, 1137, 1138, 3, 117, 49, 0, 1138, 1139, 1, 0, 0, 0, 1139, 1140, 6, 100, 20, 0, 1140, 220, 1, 0, 0, 0, 1141, 1142, 3, 119, 50, 0, 1142, 1143, 1, 0, 0, 0, 1143, 1144, 6, 101, 21, 0, 1144, 222, 1, 0, 0, 0, 1145, 1146, 3, 113, 47, 0, 1146, 1147, 1, 0, 0, 0, 1147, 1148, 6, 102, 22, 0, 1148, 224, 1, 0, 0, 0, 1149, 1150, 7, 16, 0, 0, 1150, 1151, 7, 3, 0, 0, 1151, 1152, 7, 5, 0, 0, 1152, 1153, 7, 12, 0, 0, 1153, 1154, 7, 0, 0, 0, 1154, 1155, 7, 12, 0, 0, 1155, 1156, 7, 5, 0, 0, 1156, 1157, 7, 12, 0, 0, 1157, 226, 1, 0, 0, 0, 1158, 1162, 8, 32, 0, 0, 1159, 1160, 5, 47, 0, 0, 1160, 1162, 8, 33, 0, 0, 1161, 1158, 1, 0, 0, 0, 1161, 1159, 1, 0, 0, 0, 1162, 228, 1, 0, 0, 0, 1163, 1165, 3, 227, 104, 0, 1164, 1163, 1, 0, 0, 0, 1165, 1166, 1, 0, 0, 0, 1166, 1164, 1, 0, 0, 0, 1166, 1167, 1, 0, 0, 0, 1167, 230, 1, 0, 0, 0, 1168, 1169, 3, 229, 105, 0, 1169, 1170, 1, 0, 0, 0, 1170, 1171, 6, 106, 23, 0, 1171, 232, 1, 0, 0, 0, 1172, 1173, 3, 101, 41, 0, 1173, 1174, 1, 0, 0, 0, 1174, 1175, 6, 107, 24, 0, 1175, 234, 1, 0, 0, 0, 1176, 1177, 3, 73, 27, 0, 1177, 1178, 1, 0, 0, 0, 1178, 1179, 6, 108, 13, 0, 1179, 236, 1, 0, 0, 0, 1180, 1181, 3, 75, 28, 0, 1181, 1182, 1, 0, 0, 0, 1182, 1183, 6, 109, 13, 0, 1183, 238, 1, 0, 0, 0, 1184, 1185, 3, 77, 29, 0, 1185, 1186, 1, 0, 0, 0, 1186, 1187, 6, 110, 13, 0, 1187, 240, 1, 0, 0, 0, 1188, 1189, 3, 79, 30, 0, 1189, 1190, 1, 0, 0, 0, 1190, 1191, 6, 111, 18, 0, 1191, 1192, 6, 111, 14, 0, 1192, 242, 1, 0, 0, 0, 1193, 1194, 3, 123, 52, 0, 1194, 1195, 1, 0, 0, 0, 1195, 1196, 6, 112, 25, 0, 1196, 244, 1, 0, 0, 0, 1197, 1198, 3, 119, 50, 0, 1198, 1199, 1, 0, 0, 0, 1199, 1200, 6, 113, 21, 0, 1200, 246, 1, 0, 0, 0, 1201, 1202, 3, 145, 63, 0, 1202, 1203, 1, 0, 0, 0, 1203, 1204, 6, 114, 26, 0, 1204, 248, 1, 0, 0, 0, 1205, 1206, 3, 181, 81, 0, 1206, 1207, 1, 0, 0, 0, 1207, 1208, 6, 115, 27, 0, 1208, 250, 1, 0, 0, 0, 1209, 1214, 3, 83, 32, 0, 1210, 1214, 3, 81, 31, 0, 1211, 1214, 3, 97, 39, 0, 1212, 1214, 3, 169, 75, 0, 1213, 1209, 1, 0, 0, 0, 1213, 1210, 1, 0, 0, 0, 1213, 1211, 1, 0, 0, 0, 1213, 1212, 1, 0, 0, 0, 1214, 252, 1, 0, 0, 0, 1215, 1218, 3, 83, 32, 0, 1216, 1218, 3, 169, 75, 0, 1217, 1215, 1, 0, 0, 0, 1217, 1216, 1, 0, 0, 0, 1218, 1222, 1, 0, 0, 0, 1219, 1221, 3, 251, 116, 0, 1220, 1219, 1, 0, 0, 0, 1221, 1224, 1, 0, 0, 0, 1222, 1220, 1, 0, 0, 0, 1222, 1223, 1, 0, 0, 0, 1223, 1235, 1, 0, 0, 0, 1224, 1222, 1, 0, 0, 0, 1225, 1228, 3, 97, 39, 0, 1226, 1228, 3, 91, 36, 0, 1227, 1225, 1, 0, 0, 0, 1227, 1226, 1, 0, 0, 0, 1228, 1230, 1, 0, 0, 0, 1229, 1231, 3, 251, 116, 0, 1230, 1229, 1, 0, 0, 0, 1231, 1232, 1, 0, 0, 0, 1232, 1230, 1, 0, 0, 0, 1232, 1233, 1, 0, 0, 0, 1233, 1235, 1, 0, 0, 0, 1234, 1217, 1, 0, 0, 0, 1234, 1227, 1, 0, 0, 0, 1235, 254, 1, 0, 0, 0, 1236, 1239, 3, 253, 117, 0, 1237, 1239, 3, 193, 87, 0, 1238, 1236, 1, 0, 0, 0, 1238, 1237, 1, 0, 0, 0, 1239, 1240, 1, 0, 0, 0, 1240, 1238, 1, 0, 0, 0, 1240, 1241, 1, 0, 0, 0, 1241, 256, 1, 0, 0, 0, 1242, 1243, 3, 73, 27, 0, 1243, 1244, 1, 0, 0, 0, 1244, 1245, 6, 119, 13, 0, 1245, 258, 1, 0, 0, 0, 1246, 1247, 3, 75, 28, 0, 1247, 1248, 1, 0, 0, 0, 1248, 1249, 6, 120, 13, 0, 1249, 260, 1, 0, 0, 0, 1250, 1251, 3, 77, 29, 0, 1251, 1252, 1, 0, 0, 0, 1252, 1253, 6, 121, 13, 0, 1253, 262, 1, 0, 0, 0, 1254, 1255, 3, 79, 30, 0, 1255, 1256, 1, 0, 0, 0, 1256, 1257, 6, 122, 18, 0, 1257, 1258, 6, 122, 14, 0, 1258, 264, 1, 0, 0, 0, 1259, 1260, 3, 113, 47, 0, 1260, 1261, 1, 0, 0, 0, 1261, 1262, 6, 123, 22, 0, 1262, 266, 1, 0, 0, 0, 1263, 1264, 3, 119, 50, 0, 1264, 1265, 1, 0, 0, 0, 1265, 1266, 6, 124, 21, 0, 1266, 268, 1, 0, 0, 0, 1267, 1268, 3, 123, 52, 0, 1268, 1269, 1, 0, 0, 0, 1269, 1270, 6, 125, 25, 0, 1270, 270, 1, 0, 0, 0, 1271, 1272, 3, 145, 63, 0, 1272, 1273, 1, 0, 0, 0, 1273, 1274, 6, 126, 26, 0, 1274, 272, 1, 0, 0, 0, 1275, 1276, 3, 181, 81, 0, 1276, 1277, 1, 0, 0, 0, 1277, 1278, 6, 127, 27, 0, 1278, 274, 1, 0, 0, 0, 1279, 1280, 7, 12, 0, 0, 1280, 1281, 7, 2, 0, 0, 1281, 276, 1, 0, 0, 0, 1282, 1283, 3, 255, 118, 0, 1283, 1284, 1, 0, 0, 0, 1284, 1285, 6, 129, 28, 0, 1285, 278, 1, 0, 0, 0, 1286, 1287, 3, 73, 27, 0, 1287, 1288, 1, 0, 0, 0, 1288, 1289, 6, 130, 13, 0, 1289, 280, 1, 0, 0, 0, 1290, 1291, 3, 75, 28, 0, 1291, 1292, 1, 0, 0, 0, 1292, 1293, 6, 131, 13, 0, 1293, 282, 1, 0, 0, 0, 1294, 1295, 3, 77, 29, 0, 1295, 1296, 1, 0, 0, 0, 1296, 1297, 6, 132, 13, 0, 1297, 284, 1, 0, 0, 0, 1298, 1299, 3, 79, 30, 0, 1299, 1300, 1, 0, 0, 0, 1300, 1301, 6, 133, 18, 0, 1301, 1302, 6, 133, 14, 0, 1302, 286, 1, 0, 0, 0, 1303, 1304, 3, 183, 82, 0, 1304, 1305, 1, 0, 0, 0, 1305, 1306, 6, 134, 16, 0, 1306, 1307, 6, 134, 29, 0, 1307, 288, 1, 0, 0, 0, 1308, 1309, 7, 7, 0, 0, 1309, 1310, 7, 9, 0, 0, 1310, 1311, 1, 0, 0, 0, 1311, 1312, 6, 135, 30, 0, 1312, 290, 1, 0, 0, 0, 1313, 1314, 7, 19, 0, 0, 1314, 1315, 7, 1, 0, 0, 1315, 1316, 7, 5, 0, 0, 1316, 1317, 7, 10, 0, 0, 1317, 1318, 1, 0, 0, 0, 1318, 1319, 6, 136, 30, 0, 1319, 292, 1, 0, 0, 0, 1320, 1321, 8, 34, 0, 0, 1321, 294, 1, 0, 0, 0, 1322, 1324, 3, 293, 137, 0, 1323, 1322, 1, 0, 0, 0, 1324, 1325, 1, 0, 0, 0, 1325, 1323, 1, 0, 0, 0, 1325, 1326, 1, 0, 0, 0, 1326, 1327, 1, 0, 0, 0, 1327, 1328, 3, 117, 49, 0, 1328, 1330, 1, 0, 0, 0, 1329, 1323, 1, 0, 0, 0, 1329, 1330, 1, 0, 0, 0, 1330, 1332, 1, 0, 0, 0, 1331, 1333, 3, 293, 137, 0, 1332, 1331, 1, 0, 0, 0, 1333, 1334, 1, 0, 0, 0, 1334, 1332, 1, 0, 0, 0, 1334, 1335, 1, 0, 0, 0, 1335, 296, 1, 0, 0, 0, 1336, 1337, 3, 295, 138, 0, 1337, 1338, 1, 0, 0, 0, 1338, 1339, 6, 139, 31, 0, 1339, 298, 1, 0, 0, 0, 1340, 1341, 3, 73, 27, 0, 1341, 1342, 1, 0, 0, 0, 1342, 1343, 6, 140, 13, 0, 1343, 300, 1, 0, 0, 0, 1344, 1345, 3, 75, 28, 0, 1345, 1346, 1, 0, 0, 0, 1346, 1347, 6, 141, 13, 0, 1347, 302, 1, 0, 0, 0, 1348, 1349, 3, 77, 29, 0, 1349, 1350, 1, 0, 0, 0, 1350, 1351, 6, 142, 13, 0, 1351, 304, 1, 0, 0, 0, 1352, 1353, 3, 79, 30, 0, 1353, 1354, 1, 0, 0, 0, 1354, 1355, 6, 143, 18, 0, 1355, 1356, 6, 143, 14, 0, 1356, 1357, 6, 143, 14, 0, 1357, 306, 1, 0, 0, 0, 1358, 1359, 3, 113, 47, 0, 1359, 1360, 1, 0, 0, 0, 1360, 1361, 6, 144, 22, 0, 1361, 308, 1, 0, 0, 0, 1362, 1363, 3, 119, 50, 0, 1363, 1364, 1, 0, 0, 0, 1364, 1365, 6, 145, 21, 0, 1365, 310, 1, 0, 0, 0, 1366, 1367, 3, 123, 52, 0, 1367, 1368, 1, 0, 0, 0, 1368, 1369, 6, 146, 25, 0, 1369, 312, 1, 0, 0, 0, 1370, 1371, 3, 291, 136, 0, 1371, 1372, 1, 0, 0, 0, 1372, 1373, 6, 147, 32, 0, 1373, 314, 1, 0, 0, 0, 1374, 1375, 3, 255, 118, 0, 1375, 1376, 1, 0, 0, 0, 1376, 1377, 6, 148, 28, 0, 1377, 316, 1, 0, 0, 0, 1378, 1379, 3, 195, 88, 0, 1379, 1380, 1, 0, 0, 0, 1380, 1381, 6, 149, 33, 0, 1381, 318, 1, 0, 0, 0, 1382, 1383, 3, 145, 63, 0, 1383, 1384, 1, 0, 0, 0, 1384, 1385, 6, 150, 26, 0, 1385, 320, 1, 0, 0, 0, 1386, 1387, 3, 181, 81, 0, 1387, 1388, 1, 0, 0, 0, 1388, 1389, 6, 151, 27, 0, 1389, 322, 1, 0, 0, 0, 1390, 1391, 3, 73, 27, 0, 1391, 1392, 1, 0, 0, 0, 1392, 1393, 6, 152, 13, 0, 1393, 324, 1, 0, 0, 0, 1394, 1395, 3, 75, 28, 0, 1395, 1396, 1, 0, 0, 0, 1396, 1397, 6, 153, 13, 0, 1397, 326, 1, 0, 0, 0, 1398, 1399, 3, 77, 29, 0, 1399, 1400, 1, 0, 0, 0, 1400, 1401, 6, 154, 13, 0, 1401, 328, 1, 0, 0, 0, 1402, 1403, 3, 79, 30, 0, 1403, 1404, 1, 0, 0, 0, 1404, 1405, 6, 155, 18, 0, 1405, 1406, 6, 155, 14, 0, 1406, 330, 1, 0, 0, 0, 1407, 1408, 3, 123, 52, 0, 1408, 1409, 1, 0, 0, 0, 1409, 1410, 6, 156, 25, 0, 1410, 332, 1, 0, 0, 0, 1411, 1412, 3, 145, 63, 0, 1412, 1413, 1, 0, 0, 0, 1413, 1414, 6, 157, 26, 0, 1414, 334, 1, 0, 0, 0, 1415, 1416, 3, 181, 81, 0, 1416, 1417, 1, 0, 0, 0, 1417, 1418, 6, 158, 27, 0, 1418, 336, 1, 0, 0, 0, 1419, 1420, 3, 195, 88, 0, 1420, 1421, 1, 0, 0, 0, 1421, 1422, 6, 159, 33, 0, 1422, 338, 1, 0, 0, 0, 1423, 1424, 3, 191, 86, 0, 1424, 1425, 1, 0, 0, 0, 1425, 1426, 6, 160, 34, 0, 1426, 340, 1, 0, 0, 0, 1427, 1428, 3, 73, 27, 0, 1428, 1429, 1, 0, 0, 0, 1429, 1430, 6, 161, 13, 0, 1430, 342, 1, 0, 0, 0, 1431, 1432, 3, 75, 28, 0, 1432, 1433, 1, 0, 0, 0, 1433, 1434, 6, 162, 13, 0, 1434, 344, 1, 0, 0, 0, 1435, 1436, 3, 77, 29, 0, 1436, 1437, 1, 0, 0, 0, 1437, 1438, 6, 163, 13, 0, 1438, 346, 1, 0, 0, 0, 1439, 1440, 3, 79, 30, 0, 1440, 1441, 1, 0, 0, 0, 1441, 1442, 6, 164, 18, 0, 1442, 1443, 6, 164, 14, 0, 1443, 348, 1, 0, 0, 0, 1444, 1445, 7, 1, 0, 0, 1445, 1446, 7, 9, 0, 0, 1446, 1447, 7, 15, 0, 0, 1447, 1448, 7, 7, 0, 0, 1448, 350, 1, 0, 0, 0, 1449, 1450, 3, 73, 27, 0, 1450, 1451, 1, 0, 0, 0, 1451, 1452, 6, 166, 13, 0, 1452, 352, 1, 0, 0, 0, 1453, 1454, 3, 75, 28, 0, 1454, 1455, 1, 0, 0, 0, 1455, 1456, 6, 167, 13, 0, 1456, 354, 1, 0, 0, 0, 1457, 1458, 3, 77, 29, 0, 1458, 1459, 1, 0, 0, 0, 1459, 1460, 6, 168, 13, 0, 1460, 356, 1, 0, 0, 0, 1461, 1462, 3, 185, 83, 0, 1462, 1463, 1, 0, 0, 0, 1463, 1464, 6, 169, 19, 0, 1464, 1465, 6, 169, 14, 0, 1465, 358, 1, 0, 0, 0, 1466, 1467, 3, 117, 49, 0, 1467, 1468, 1, 0, 0, 0, 1468, 1469, 6, 170, 20, 0, 1469, 360, 1, 0, 0, 0, 1470, 1476, 3, 91, 36, 0, 1471, 1476, 3, 81, 31, 0, 1472, 1476, 3, 123, 52, 0, 1473, 1476, 3, 83, 32, 0, 1474, 1476, 3, 97, 39, 0, 1475, 1470, 1, 0, 0, 0, 1475, 1471, 1, 0, 0, 0, 1475, 1472, 1, 0, 0, 0, 1475, 1473, 1, 0, 0, 0, 1475, 1474, 1, 0, 0, 0, 1476, 1477, 1, 0, 0, 0, 1477, 1475, 1, 0, 0, 0, 1477, 1478, 1, 0, 0, 0, 1478, 362, 1, 0, 0, 0, 1479, 1480, 3, 73, 27, 0, 1480, 1481, 1, 0, 0, 0, 1481, 1482, 6, 172, 13, 0, 1482, 364, 1, 0, 0, 0, 1483, 1484, 3, 75, 28, 0, 1484, 1485, 1, 0, 0, 0, 1485, 1486, 6, 173, 13, 0, 1486, 366, 1, 0, 0, 0, 1487, 1488, 3, 77, 29, 0, 1488, 1489, 1, 0, 0, 0, 1489, 1490, 6, 174, 13, 0, 1490, 368, 1, 0, 0, 0, 1491, 1492, 3, 79, 30, 0, 1492, 1493, 1, 0, 0, 0, 1493, 1494, 6, 175, 18, 0, 1494, 1495, 6, 175, 14, 0, 1495, 370, 1, 0, 0, 0, 1496, 1497, 3, 117, 49, 0, 1497, 1498, 1, 0, 0, 0, 1498, 1499, 6, 176, 20, 0, 1499, 372, 1, 0, 0, 0, 1500, 1501, 3, 119, 50, 0, 1501, 1502, 1, 0, 0, 0, 1502, 1503, 6, 177, 21, 0, 1503, 374, 1, 0, 0, 0, 1504, 1505, 3, 123, 52, 0, 1505, 1506, 1, 0, 0, 0, 1506, 1507, 6, 178, 25, 0, 1507, 376, 1, 0, 0, 0, 1508, 1509, 3, 289, 135, 0, 1509, 1510, 1, 0, 0, 0, 1510, 1511, 6, 179, 35, 0, 1511, 1512, 6, 179, 36, 0, 1512, 378, 1, 0, 0, 0, 1513, 1514, 3, 229, 105, 0, 1514, 1515, 1, 0, 0, 0, 1515, 1516, 6, 180, 23, 0, 1516, 380, 1, 0, 0, 0, 1517, 1518, 3, 101, 41, 0, 1518, 1519, 1, 0, 0, 0, 1519, 1520, 6, 181, 24, 0, 1520, 382, 1, 0, 0, 0, 1521, 1522, 3, 73, 27, 0, 1522, 1523, 1, 0, 0, 0, 1523, 1524, 6, 182, 13, 0, 1524, 384, 1, 0, 0, 0, 1525, 1526, 3, 75, 28, 0, 1526, 1527, 1, 0, 0, 0, 1527, 1528, 6, 183, 13, 0, 1528, 386, 1, 0, 0, 0, 1529, 1530, 3, 77, 29, 0, 1530, 1531, 1, 0, 0, 0, 1531, 1532, 6, 184, 13, 0, 1532, 388, 1, 0, 0, 0, 1533, 1534, 3, 79, 30, 0, 1534, 1535, 1, 0, 0, 0, 1535, 1536, 6, 185, 18, 0, 1536, 1537, 6, 185, 14, 0, 1537, 1538, 6, 185, 14, 0, 1538, 390, 1, 0, 0, 0, 1539, 1540, 3, 119, 50, 0, 1540, 1541, 1, 0, 0, 0, 1541, 1542, 6, 186, 21, 0, 1542, 392, 1, 0, 0, 0, 1543, 1544, 3, 123, 52, 0, 1544, 1545, 1, 0, 0, 0, 1545, 1546, 6, 187, 25, 0, 1546, 394, 1, 0, 0, 0, 1547, 1548, 3, 255, 118, 0, 1548, 1549, 1, 0, 0, 0, 1549, 1550, 6, 188, 28, 0, 1550, 396, 1, 0, 0, 0, 1551, 1552, 3, 73, 27, 0, 1552, 1553, 1, 0, 0, 0, 1553, 1554, 6, 189, 13, 0, 1554, 398, 1, 0, 0, 0, 1555, 1556, 3, 75, 28, 0, 1556, 1557, 1, 0, 0, 0, 1557, 1558, 6, 190, 13, 0, 1558, 400, 1, 0, 0, 0, 1559, 1560, 3, 77, 29, 0, 1560, 1561, 1, 0, 0, 0, 1561, 1562, 6, 191, 13, 0, 1562, 402, 1, 0, 0, 0, 1563, 1564, 3, 79, 30, 0, 1564, 1565, 1, 0, 0, 0, 1565, 1566, 6, 192, 18, 0, 1566, 1567, 6, 192, 14, 0, 1567, 404, 1, 0, 0, 0, 1568, 1569, 7, 35, 0, 0, 1569, 1570, 7, 7, 0, 0, 1570, 1571, 7, 1, 0, 0, 1571, 1572, 7, 9, 0, 0, 1572, 406, 1, 0, 0, 0, 1573, 1574, 3, 275, 128, 0, 1574, 1575, 1, 0, 0, 0, 1575, 1576, 6, 194, 37, 0, 1576, 408, 1, 0, 0, 0, 1577, 1578, 3, 289, 135, 0, 1578, 1579, 1, 0, 0, 0, 1579, 1580, 6, 195, 35, 0, 1580, 1581, 6, 195, 14, 0, 1581, 1582, 6, 195, 0, 0, 1582, 410, 1, 0, 0, 0, 1583, 1584, 7, 20, 0, 0, 1584, 1585, 7, 2, 0, 0, 1585, 1586, 7, 1, 0, 0, 1586, 1587, 7, 9, 0, 0, 1587, 1588, 7, 17, 0, 0, 1588, 1589, 1, 0, 0, 0, 1589, 1590, 6, 196, 14, 0, 1590, 1591, 6, 196, 0, 0, 1591, 412, 1, 0, 0, 0, 1592, 1593, 3, 229, 105, 0, 1593, 1594, 1, 0, 0, 0, 1594, 1595, 6, 197, 23, 0, 1595, 414, 1, 0, 0, 0, 1596, 1597, 3, 101, 41, 0, 1597, 1598, 1, 0, 0, 0, 1598, 1599, 6, 198, 24, 0, 1599, 416, 1, 0, 0, 0, 1600, 1601, 3, 117, 49, 0, 1601, 1602, 1, 0, 0, 0, 1602, 1603, 6, 199, 20, 0, 1603, 418, 1, 0, 0, 0, 1604, 1605, 3, 191, 86, 0, 1605, 1606, 1, 0, 0, 0, 1606, 1607, 6, 200, 34, 0, 1607, 420, 1, 0, 0, 0, 1608, 1609, 3, 195, 88, 0, 1609, 1610, 1, 0, 0, 0, 1610, 1611, 6, 201, 33, 0, 1611, 422, 1, 0, 0, 0, 1612, 1613, 3, 73, 27, 0, 1613, 1614, 1, 0, 0, 0, 1614, 1615, 6, 202, 13, 0, 1615, 424, 1, 0, 0, 0, 1616, 1617, 3, 75, 28, 0, 1617, 1618, 1, 0, 0, 0, 1618, 1619, 6, 203, 13, 0, 1619, 426, 1, 0, 0, 0, 1620, 1621, 3, 77, 29, 0, 1621, 1622, 1, 0, 0, 0, 1622, 1623, 6, 204, 13, 0, 1623, 428, 1, 0, 0, 0, 1624, 1625, 3, 79, 30, 0, 1625, 1626, 1, 0, 0, 0, 1626, 1627, 6, 205, 18, 0, 1627, 1628, 6, 205, 14, 0, 1628, 430, 1, 0, 0, 0, 1629, 1630, 3, 229, 105, 0, 1630, 1631, 1, 0, 0, 0, 1631, 1632, 6, 206, 23, 0, 1632, 1633, 6, 206, 14, 0, 1633, 1634, 6, 206, 38, 0, 1634, 432, 1, 0, 0, 0, 1635, 1636, 3, 101, 41, 0, 1636, 1637, 1, 0, 0, 0, 1637, 1638, 6, 207, 24, 0, 1638, 1639, 6, 207, 14, 0, 1639, 1640, 6, 207, 38, 0, 1640, 434, 1, 0, 0, 0, 1641, 1642, 3, 73, 27, 0, 1642, 1643, 1, 0, 0, 0, 1643, 1644, 6, 208, 13, 0, 1644, 436, 1, 0, 0, 0, 1645, 1646, 3, 75, 28, 0, 1646, 1647, 1, 0, 0, 0, 1647, 1648, 6, 209, 13, 0, 1648, 438, 1, 0, 0, 0, 1649, 1650, 3, 77, 29, 0, 1650, 1651, 1, 0, 0, 0, 1651, 1652, 6, 210, 13, 0, 1652, 440, 1, 0, 0, 0, 1653, 1654, 3, 117, 49, 0, 1654, 1655, 1, 0, 0, 0, 1655, 1656, 6, 211, 20, 0, 1656, 1657, 6, 211, 14, 0, 1657, 1658, 6, 211, 11, 0, 1658, 442, 1, 0, 0, 0, 1659, 1660, 3, 119, 50, 0, 1660, 1661, 1, 0, 0, 0, 1661, 1662, 6, 212, 21, 0, 1662, 1663, 6, 212, 14, 0, 1663, 1664, 6, 212, 11, 0, 1664, 444, 1, 0, 0, 0, 1665, 1666, 3, 73, 27, 0, 1666, 1667, 1, 0, 0, 0, 1667, 1668, 6, 213, 13, 0, 1668, 446, 1, 0, 0, 0, 1669, 1670, 3, 75, 28, 0, 1670, 1671, 1, 0, 0, 0, 1671, 1672, 6, 214, 13, 0, 1672, 448, 1, 0, 0, 0, 1673, 1674, 3, 77, 29, 0, 1674, 1675, 1, 0, 0, 0, 1675, 1676, 6, 215, 13, 0, 1676, 450, 1, 0, 0, 0, 1677, 1678, 3, 195, 88, 0, 1678, 1679, 1, 0, 0, 0, 1679, 1680, 6, 216, 14, 0, 1680, 1681, 6, 216, 0, 0, 1681, 1682, 6, 216, 33, 0, 1682, 452, 1, 0, 0, 0, 1683, 1684, 3, 191, 86, 0, 1684, 1685, 1, 0, 0, 0, 1685, 1686, 6, 217, 14, 0, 1686, 1687, 6, 217, 0, 0, 1687, 1688, 6, 217, 34, 0, 1688, 454, 1, 0, 0, 0, 1689, 1690, 3, 107, 44, 0, 1690, 1691, 1, 0, 0, 0, 1691, 1692, 6, 218, 14, 0, 1692, 1693, 6, 218, 0, 0, 1693, 1694, 6, 218, 39, 0, 1694, 456, 1, 0, 0, 0, 1695, 1696, 3, 79, 30, 0, 1696, 1697, 1, 0, 0, 0, 1697, 1698, 6, 219, 18, 0, 1698, 1699, 6, 219, 14, 0, 1699, 458, 1, 0, 0, 0, 1700, 1701, 3, 79, 30, 0, 1701, 1702, 1, 0, 0, 0, 1702, 1703, 6, 220, 18, 0, 1703, 1704, 6, 220, 14, 0, 1704, 460, 1, 0, 0, 0, 1705, 1706, 3, 289, 135, 0, 1706, 1707, 1, 0, 0, 0, 1707, 1708, 6, 221, 35, 0, 1708, 462, 1, 0, 0, 0, 1709, 1710, 3, 275, 128, 0, 1710, 1711, 1, 0, 0, 0, 1711, 1712, 6, 222, 37, 0, 1712, 464, 1, 0, 0, 0, 1713, 1714, 3, 123, 52, 0, 1714, 1715, 1, 0, 0, 0, 1715, 1716, 6, 223, 25, 0, 1716, 466, 1, 0, 0, 0, 1717, 1718, 3, 119, 50, 0, 1718, 1719, 1, 0, 0, 0, 1719, 1720, 6, 224, 21, 0, 1720, 468, 1, 0, 0, 0, 1721, 1722, 3, 195, 88, 0, 1722, 1723, 1, 0, 0, 0, 1723, 1724, 6, 225, 33, 0, 1724, 470, 1, 0, 0, 0, 1725, 1726, 3, 191, 86, 0, 1726, 1727, 1, 0, 0, 0, 1727, 1728, 6, 226, 34, 0, 1728, 472, 1, 0, 0, 0, 1729, 1730, 3, 73, 27, 0, 1730, 1731, 1, 0, 0, 0, 1731, 1732, 6, 227, 13, 0, 1732, 474, 1, 0, 0, 0, 1733, 1734, 3, 75, 28, 0, 1734, 1735, 1, 0, 0, 0, 1735, 1736, 6, 228, 13, 0, 1736, 476, 1, 0, 0, 0, 1737, 1738, 3, 77, 29, 0, 1738, 1739, 1, 0, 0, 0, 1739, 1740, 6, 229, 13, 0, 1740, 478, 1, 0, 0, 0, 1741, 1742, 3, 79, 30, 0, 1742, 1743, 1, 0, 0, 0, 1743, 1744, 6, 230, 18, 0, 1744, 1745, 6, 230, 14, 0, 1745, 480, 1, 0, 0, 0, 1746, 1747, 3, 191, 86, 0, 1747, 1748, 1, 0, 0, 0, 1748, 1749, 6, 231, 34, 0, 1749, 482, 1, 0, 0, 0, 1750, 1751, 3, 77, 29, 0, 1751, 1752, 1, 0, 0, 0, 1752, 1753, 6, 232, 13, 0, 1753, 484, 1, 0, 0, 0, 1754, 1755, 3, 73, 27, 0, 1755, 1756, 1, 0, 0, 0, 1756, 1757, 6, 233, 13, 0, 1757, 486, 1, 0, 0, 0, 1758, 1759, 3, 75, 28, 0, 1759, 1760, 1, 0, 0, 0, 1760, 1761, 6, 234, 13, 0, 1761, 488, 1, 0, 0, 0, 1762, 1763, 3, 187, 84, 0, 1763, 1764, 1, 0, 0, 0, 1764, 1765, 6, 235, 40, 0, 1765, 1766, 6, 235, 17, 0, 1766, 490, 1, 0, 0, 0, 1767, 1768, 3, 79, 30, 0, 1768, 1769, 1, 0, 0, 0, 1769, 1770, 6, 236, 18, 0, 1770, 1771, 6, 236, 14, 0, 1771, 492, 1, 0, 0, 0, 1772, 1773, 3, 77, 29, 0, 1773, 1774, 1, 0, 0, 0, 1774, 1775, 6, 237, 13, 0, 1775, 494, 1, 0, 0, 0, 1776, 1777, 3, 73, 27, 0, 1777, 1778, 1, 0, 0, 0, 1778, 1779, 6, 238, 13, 0, 1779, 496, 1, 0, 0, 0, 1780, 1781, 3, 75, 28, 0, 1781, 1782, 1, 0, 0, 0, 1782, 1783, 6, 239, 13, 0, 1783, 498, 1, 0, 0, 0, 69, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 739, 749, 753, 756, 765, 767, 778, 797, 802, 811, 818, 823, 825, 836, 844, 847, 849, 854, 859, 865, 872, 877, 883, 886, 894, 898, 1026, 1031, 1038, 1040, 1066, 1071, 1076, 1078, 1084, 1161, 1166, 1213, 1217, 1222, 1227, 1232, 1234, 1238, 1240, 1325, 1329, 1334, 1475, 1477, 41, 5, 1, 0, 5, 4, 0, 5, 6, 0, 5, 2, 0, 5, 3, 0, 5, 8, 0, 5, 5, 0, 5, 9, 0, 5, 13, 0, 5, 16, 0, 5, 11, 0, 5, 14, 0, 5, 18, 0, 0, 1, 0, 4, 0, 0, 7, 16, 0, 7, 72, 0, 5, 0, 0, 7, 31, 0, 7, 73, 0, 7, 40, 0, 7, 41, 0, 7, 38, 0, 7, 85, 0, 7, 32, 0, 7, 43, 0, 7, 54, 0, 7, 71, 0, 7, 89, 0, 5, 10, 0, 5, 7, 0, 7, 99, 0, 7, 98, 0, 7, 77, 0, 7, 76, 0, 7, 97, 0, 5, 12, 0, 7, 93, 0, 5, 15, 0, 7, 35, 0, 7, 74, 0] \ No newline at end of file diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java index 08c17791963c..16e0455c6b45 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseLexer.java @@ -32,21 +32,21 @@ public class EsqlBaseLexer extends LexerConfig { DEV_FORK=26, UNKNOWN_CMD=27, LINE_COMMENT=28, MULTILINE_COMMENT=29, WS=30, PIPE=31, QUOTED_STRING=32, INTEGER_LITERAL=33, DECIMAL_LITERAL=34, BY=35, AND=36, ASC=37, ASSIGN=38, CAST_OP=39, COLON=40, COMMA=41, DESC=42, DOT=43, - FALSE=44, FIRST=45, IN=46, IS=47, LAST=48, LIKE=49, LP=50, NOT=51, NULL=52, - NULLS=53, OR=54, PARAM=55, RLIKE=56, RP=57, TRUE=58, EQ=59, CIEQ=60, NEQ=61, - LT=62, LTE=63, GT=64, GTE=65, PLUS=66, MINUS=67, ASTERISK=68, SLASH=69, - PERCENT=70, LEFT_BRACES=71, RIGHT_BRACES=72, NAMED_OR_POSITIONAL_PARAM=73, - OPENING_BRACKET=74, CLOSING_BRACKET=75, UNQUOTED_IDENTIFIER=76, QUOTED_IDENTIFIER=77, - EXPR_LINE_COMMENT=78, EXPR_MULTILINE_COMMENT=79, EXPR_WS=80, EXPLAIN_WS=81, - EXPLAIN_LINE_COMMENT=82, EXPLAIN_MULTILINE_COMMENT=83, METADATA=84, UNQUOTED_SOURCE=85, - FROM_LINE_COMMENT=86, FROM_MULTILINE_COMMENT=87, FROM_WS=88, ID_PATTERN=89, - PROJECT_LINE_COMMENT=90, PROJECT_MULTILINE_COMMENT=91, PROJECT_WS=92, - AS=93, RENAME_LINE_COMMENT=94, RENAME_MULTILINE_COMMENT=95, RENAME_WS=96, - ON=97, WITH=98, ENRICH_POLICY_NAME=99, ENRICH_LINE_COMMENT=100, ENRICH_MULTILINE_COMMENT=101, - ENRICH_WS=102, ENRICH_FIELD_LINE_COMMENT=103, ENRICH_FIELD_MULTILINE_COMMENT=104, - ENRICH_FIELD_WS=105, MVEXPAND_LINE_COMMENT=106, MVEXPAND_MULTILINE_COMMENT=107, - MVEXPAND_WS=108, INFO=109, SHOW_LINE_COMMENT=110, SHOW_MULTILINE_COMMENT=111, - SHOW_WS=112, SETTING=113, SETTING_LINE_COMMENT=114, SETTTING_MULTILINE_COMMENT=115, + FALSE=44, FIRST=45, IN=46, IS=47, LAST=48, LIKE=49, NOT=50, NULL=51, NULLS=52, + OR=53, PARAM=54, RLIKE=55, TRUE=56, EQ=57, CIEQ=58, NEQ=59, LT=60, LTE=61, + GT=62, GTE=63, PLUS=64, MINUS=65, ASTERISK=66, SLASH=67, PERCENT=68, LEFT_BRACES=69, + RIGHT_BRACES=70, NAMED_OR_POSITIONAL_PARAM=71, OPENING_BRACKET=72, CLOSING_BRACKET=73, + LP=74, RP=75, UNQUOTED_IDENTIFIER=76, QUOTED_IDENTIFIER=77, EXPR_LINE_COMMENT=78, + EXPR_MULTILINE_COMMENT=79, EXPR_WS=80, EXPLAIN_WS=81, EXPLAIN_LINE_COMMENT=82, + EXPLAIN_MULTILINE_COMMENT=83, METADATA=84, UNQUOTED_SOURCE=85, FROM_LINE_COMMENT=86, + FROM_MULTILINE_COMMENT=87, FROM_WS=88, ID_PATTERN=89, PROJECT_LINE_COMMENT=90, + PROJECT_MULTILINE_COMMENT=91, PROJECT_WS=92, AS=93, RENAME_LINE_COMMENT=94, + RENAME_MULTILINE_COMMENT=95, RENAME_WS=96, ON=97, WITH=98, ENRICH_POLICY_NAME=99, + ENRICH_LINE_COMMENT=100, ENRICH_MULTILINE_COMMENT=101, ENRICH_WS=102, + ENRICH_FIELD_LINE_COMMENT=103, ENRICH_FIELD_MULTILINE_COMMENT=104, ENRICH_FIELD_WS=105, + MVEXPAND_LINE_COMMENT=106, MVEXPAND_MULTILINE_COMMENT=107, MVEXPAND_WS=108, + INFO=109, SHOW_LINE_COMMENT=110, SHOW_MULTILINE_COMMENT=111, SHOW_WS=112, + SETTING=113, SETTING_LINE_COMMENT=114, SETTTING_MULTILINE_COMMENT=115, SETTING_WS=116, LOOKUP_LINE_COMMENT=117, LOOKUP_MULTILINE_COMMENT=118, LOOKUP_WS=119, LOOKUP_FIELD_LINE_COMMENT=120, LOOKUP_FIELD_MULTILINE_COMMENT=121, LOOKUP_FIELD_WS=122, JOIN=123, USING=124, JOIN_LINE_COMMENT=125, JOIN_MULTILINE_COMMENT=126, @@ -82,18 +82,17 @@ public class EsqlBaseLexer extends LexerConfig { "BACKQUOTE", "BACKQUOTE_BLOCK", "UNDERSCORE", "UNQUOTED_ID_BODY", "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", "ASC", "ASSIGN", "CAST_OP", "COLON", "COMMA", "DESC", "DOT", "FALSE", "FIRST", "IN", "IS", "LAST", - "LIKE", "LP", "NOT", "NULL", "NULLS", "OR", "PARAM", "RLIKE", "RP", "TRUE", - "EQ", "CIEQ", "NEQ", "LT", "LTE", "GT", "GTE", "PLUS", "MINUS", "ASTERISK", - "SLASH", "PERCENT", "LEFT_BRACES", "RIGHT_BRACES", "NESTED_WHERE", "NESTED_SORT", - "NESTED_LIMIT", "NAMED_OR_POSITIONAL_PARAM", "OPENING_BRACKET", "CLOSING_BRACKET", - "UNQUOTED_IDENTIFIER", "QUOTED_ID", "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", - "EXPR_MULTILINE_COMMENT", "EXPR_WS", "EXPLAIN_OPENING_BRACKET", "EXPLAIN_PIPE", - "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", "EXPLAIN_MULTILINE_COMMENT", "FROM_PIPE", - "FROM_OPENING_BRACKET", "FROM_CLOSING_BRACKET", "FROM_COLON", "FROM_COMMA", - "FROM_ASSIGN", "METADATA", "UNQUOTED_SOURCE_PART", "UNQUOTED_SOURCE", - "FROM_UNQUOTED_SOURCE", "FROM_QUOTED_SOURCE", "FROM_LINE_COMMENT", "FROM_MULTILINE_COMMENT", - "FROM_WS", "PROJECT_PIPE", "PROJECT_DOT", "PROJECT_COMMA", "PROJECT_PARAM", - "PROJECT_NAMED_OR_POSITIONAL_PARAM", "UNQUOTED_ID_BODY_WITH_PATTERN", + "LIKE", "NOT", "NULL", "NULLS", "OR", "PARAM", "RLIKE", "TRUE", "EQ", + "CIEQ", "NEQ", "LT", "LTE", "GT", "GTE", "PLUS", "MINUS", "ASTERISK", + "SLASH", "PERCENT", "LEFT_BRACES", "RIGHT_BRACES", "NESTED_WHERE", "NAMED_OR_POSITIONAL_PARAM", + "OPENING_BRACKET", "CLOSING_BRACKET", "LP", "RP", "UNQUOTED_IDENTIFIER", + "QUOTED_ID", "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", "EXPR_MULTILINE_COMMENT", + "EXPR_WS", "EXPLAIN_OPENING_BRACKET", "EXPLAIN_PIPE", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", + "EXPLAIN_MULTILINE_COMMENT", "FROM_PIPE", "FROM_OPENING_BRACKET", "FROM_CLOSING_BRACKET", + "FROM_COLON", "FROM_COMMA", "FROM_ASSIGN", "METADATA", "UNQUOTED_SOURCE_PART", + "UNQUOTED_SOURCE", "FROM_UNQUOTED_SOURCE", "FROM_QUOTED_SOURCE", "FROM_LINE_COMMENT", + "FROM_MULTILINE_COMMENT", "FROM_WS", "PROJECT_PIPE", "PROJECT_DOT", "PROJECT_COMMA", + "PROJECT_PARAM", "PROJECT_NAMED_OR_POSITIONAL_PARAM", "UNQUOTED_ID_BODY_WITH_PATTERN", "UNQUOTED_ID_PATTERN", "ID_PATTERN", "PROJECT_LINE_COMMENT", "PROJECT_MULTILINE_COMMENT", "PROJECT_WS", "RENAME_PIPE", "RENAME_ASSIGN", "RENAME_COMMA", "RENAME_DOT", "RENAME_PARAM", "RENAME_NAMED_OR_POSITIONAL_PARAM", "AS", "RENAME_ID_PATTERN", @@ -125,8 +124,8 @@ public class EsqlBaseLexer extends LexerConfig { "CHANGE_POINT_COMMA", "CHANGE_POINT_QUOTED_IDENTIFIER", "CHANGE_POINT_UNQUOTED_IDENTIFIER", "CHANGE_POINT_LINE_COMMENT", "CHANGE_POINT_MULTILINE_COMMENT", "CHANGE_POINT_WS", "INSIST_PIPE", "INSIST_IDENTIFIER", "INSIST_WS", "INSIST_LINE_COMMENT", - "INSIST_MULTILINE_COMMENT", "FORK_LP", "FORK_RP", "FORK_PIPE", "FORK_WS", - "FORK_LINE_COMMENT", "FORK_MULTILINE_COMMENT" + "INSIST_MULTILINE_COMMENT", "FORK_LP", "FORK_PIPE", "FORK_WS", "FORK_LINE_COMMENT", + "FORK_MULTILINE_COMMENT" }; } public static final String[] ruleNames = makeRuleNames(); @@ -138,10 +137,10 @@ public class EsqlBaseLexer extends LexerConfig { "'sort'", "'stats'", "'where'", "'lookup'", null, null, null, null, null, null, null, null, null, null, null, null, null, "'|'", null, null, null, "'by'", "'and'", "'asc'", "'='", "'::'", "':'", "','", "'desc'", "'.'", - "'false'", "'first'", "'in'", "'is'", "'last'", "'like'", "'('", "'not'", - "'null'", "'nulls'", "'or'", "'?'", "'rlike'", "')'", "'true'", "'=='", - "'=~'", "'!='", "'<'", "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", - "'%'", "'{'", "'}'", null, null, "']'", null, null, null, null, null, + "'false'", "'first'", "'in'", "'is'", "'last'", "'like'", "'not'", "'null'", + "'nulls'", "'or'", "'?'", "'rlike'", "'true'", "'=='", "'=~'", "'!='", + "'<'", "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", "'%'", "'{'", + "'}'", null, null, "']'", null, "')'", null, null, null, null, null, null, null, null, "'metadata'", null, null, null, null, null, null, null, null, "'as'", null, null, null, "'on'", "'with'", null, null, null, null, null, null, null, null, null, null, "'info'", null, null, null, null, @@ -158,17 +157,17 @@ public class EsqlBaseLexer extends LexerConfig { "DEV_FORK", "UNKNOWN_CMD", "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "PIPE", "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", "ASC", "ASSIGN", "CAST_OP", "COLON", "COMMA", "DESC", "DOT", "FALSE", - "FIRST", "IN", "IS", "LAST", "LIKE", "LP", "NOT", "NULL", "NULLS", "OR", - "PARAM", "RLIKE", "RP", "TRUE", "EQ", "CIEQ", "NEQ", "LT", "LTE", "GT", - "GTE", "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", "LEFT_BRACES", - "RIGHT_BRACES", "NAMED_OR_POSITIONAL_PARAM", "OPENING_BRACKET", "CLOSING_BRACKET", - "UNQUOTED_IDENTIFIER", "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", "EXPR_MULTILINE_COMMENT", - "EXPR_WS", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", "EXPLAIN_MULTILINE_COMMENT", - "METADATA", "UNQUOTED_SOURCE", "FROM_LINE_COMMENT", "FROM_MULTILINE_COMMENT", - "FROM_WS", "ID_PATTERN", "PROJECT_LINE_COMMENT", "PROJECT_MULTILINE_COMMENT", - "PROJECT_WS", "AS", "RENAME_LINE_COMMENT", "RENAME_MULTILINE_COMMENT", - "RENAME_WS", "ON", "WITH", "ENRICH_POLICY_NAME", "ENRICH_LINE_COMMENT", - "ENRICH_MULTILINE_COMMENT", "ENRICH_WS", "ENRICH_FIELD_LINE_COMMENT", + "FIRST", "IN", "IS", "LAST", "LIKE", "NOT", "NULL", "NULLS", "OR", "PARAM", + "RLIKE", "TRUE", "EQ", "CIEQ", "NEQ", "LT", "LTE", "GT", "GTE", "PLUS", + "MINUS", "ASTERISK", "SLASH", "PERCENT", "LEFT_BRACES", "RIGHT_BRACES", + "NAMED_OR_POSITIONAL_PARAM", "OPENING_BRACKET", "CLOSING_BRACKET", "LP", + "RP", "UNQUOTED_IDENTIFIER", "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", + "EXPR_MULTILINE_COMMENT", "EXPR_WS", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", + "EXPLAIN_MULTILINE_COMMENT", "METADATA", "UNQUOTED_SOURCE", "FROM_LINE_COMMENT", + "FROM_MULTILINE_COMMENT", "FROM_WS", "ID_PATTERN", "PROJECT_LINE_COMMENT", + "PROJECT_MULTILINE_COMMENT", "PROJECT_WS", "AS", "RENAME_LINE_COMMENT", + "RENAME_MULTILINE_COMMENT", "RENAME_WS", "ON", "WITH", "ENRICH_POLICY_NAME", + "ENRICH_LINE_COMMENT", "ENRICH_MULTILINE_COMMENT", "ENRICH_WS", "ENRICH_FIELD_LINE_COMMENT", "ENRICH_FIELD_MULTILINE_COMMENT", "ENRICH_FIELD_WS", "MVEXPAND_LINE_COMMENT", "MVEXPAND_MULTILINE_COMMENT", "MVEXPAND_WS", "INFO", "SHOW_LINE_COMMENT", "SHOW_MULTILINE_COMMENT", "SHOW_WS", "SETTING", "SETTING_LINE_COMMENT", @@ -262,10 +261,6 @@ public class EsqlBaseLexer extends LexerConfig { return DEV_JOIN_RIGHT_sempred((RuleContext)_localctx, predIndex); case 25: return DEV_FORK_sempred((RuleContext)_localctx, predIndex); - case 83: - return NESTED_SORT_sempred((RuleContext)_localctx, predIndex); - case 84: - return NESTED_LIMIT_sempred((RuleContext)_localctx, predIndex); } return true; } @@ -332,23 +327,9 @@ public class EsqlBaseLexer extends LexerConfig { } return true; } - private boolean NESTED_SORT_sempred(RuleContext _localctx, int predIndex) { - switch (predIndex) { - case 9: - return this.isDevVersion(); - } - return true; - } - private boolean NESTED_LIMIT_sempred(RuleContext _localctx, int predIndex) { - switch (predIndex) { - case 10: - return this.isDevVersion(); - } - return true; - } public static final String _serializedATN = - "\u0004\u0000\u008e\u0707\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+ + "\u0004\u0000\u008e\u06f8\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+ "\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+ "\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+ "\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff\uffff\u0006\uffff"+ @@ -420,7 +401,6 @@ public class EsqlBaseLexer extends LexerConfig { "\u0002\u00e7\u0007\u00e7\u0002\u00e8\u0007\u00e8\u0002\u00e9\u0007\u00e9"+ "\u0002\u00ea\u0007\u00ea\u0002\u00eb\u0007\u00eb\u0002\u00ec\u0007\u00ec"+ "\u0002\u00ed\u0007\u00ed\u0002\u00ee\u0007\u00ee\u0002\u00ef\u0007\u00ef"+ - "\u0002\u00f0\u0007\u00f0\u0002\u00f1\u0007\u00f1\u0002\u00f2\u0007\u00f2"+ "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000"+ "\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0000\u0001\u0001\u0001\u0001"+ "\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0001\u0002"+ @@ -458,1071 +438,1061 @@ public class EsqlBaseLexer extends LexerConfig { "\u0001\u0017\u0001\u0017\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018"+ "\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0018\u0001\u0019"+ "\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019\u0001\u0019"+ - "\u0001\u0019\u0001\u001a\u0004\u001a\u02e8\b\u001a\u000b\u001a\f\u001a"+ - "\u02e9\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001b\u0001"+ - "\u001b\u0005\u001b\u02f2\b\u001b\n\u001b\f\u001b\u02f5\t\u001b\u0001\u001b"+ - "\u0003\u001b\u02f8\b\u001b\u0001\u001b\u0003\u001b\u02fb\b\u001b\u0001"+ + "\u0001\u0019\u0001\u001a\u0004\u001a\u02e2\b\u001a\u000b\u001a\f\u001a"+ + "\u02e3\u0001\u001a\u0001\u001a\u0001\u001b\u0001\u001b\u0001\u001b\u0001"+ + "\u001b\u0005\u001b\u02ec\b\u001b\n\u001b\f\u001b\u02ef\t\u001b\u0001\u001b"+ + "\u0003\u001b\u02f2\b\u001b\u0001\u001b\u0003\u001b\u02f5\b\u001b\u0001"+ "\u001b\u0001\u001b\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001"+ - "\u001c\u0005\u001c\u0304\b\u001c\n\u001c\f\u001c\u0307\t\u001c\u0001\u001c"+ + "\u001c\u0005\u001c\u02fe\b\u001c\n\u001c\f\u001c\u0301\t\u001c\u0001\u001c"+ "\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001c\u0001\u001d\u0004\u001d"+ - "\u030f\b\u001d\u000b\u001d\f\u001d\u0310\u0001\u001d\u0001\u001d\u0001"+ + "\u0309\b\u001d\u000b\u001d\f\u001d\u030a\u0001\u001d\u0001\u001d\u0001"+ "\u001e\u0001\u001e\u0001\u001e\u0001\u001e\u0001\u001f\u0001\u001f\u0001"+ - " \u0001 \u0001!\u0001!\u0001!\u0001\"\u0001\"\u0001#\u0001#\u0003#\u0324"+ - "\b#\u0001#\u0004#\u0327\b#\u000b#\f#\u0328\u0001$\u0001$\u0001%\u0001"+ - "%\u0001&\u0001&\u0001&\u0003&\u0332\b&\u0001\'\u0001\'\u0001(\u0001(\u0001"+ - "(\u0003(\u0339\b(\u0001)\u0001)\u0001)\u0005)\u033e\b)\n)\f)\u0341\t)"+ - "\u0001)\u0001)\u0001)\u0001)\u0001)\u0001)\u0005)\u0349\b)\n)\f)\u034c"+ - "\t)\u0001)\u0001)\u0001)\u0001)\u0001)\u0003)\u0353\b)\u0001)\u0003)\u0356"+ - "\b)\u0003)\u0358\b)\u0001*\u0004*\u035b\b*\u000b*\f*\u035c\u0001+\u0004"+ - "+\u0360\b+\u000b+\f+\u0361\u0001+\u0001+\u0005+\u0366\b+\n+\f+\u0369\t"+ - "+\u0001+\u0001+\u0004+\u036d\b+\u000b+\f+\u036e\u0001+\u0004+\u0372\b"+ - "+\u000b+\f+\u0373\u0001+\u0001+\u0005+\u0378\b+\n+\f+\u037b\t+\u0003+"+ - "\u037d\b+\u0001+\u0001+\u0001+\u0001+\u0004+\u0383\b+\u000b+\f+\u0384"+ - "\u0001+\u0001+\u0003+\u0389\b+\u0001,\u0001,\u0001,\u0001-\u0001-\u0001"+ + " \u0001 \u0001!\u0001!\u0001!\u0001\"\u0001\"\u0001#\u0001#\u0003#\u031e"+ + "\b#\u0001#\u0004#\u0321\b#\u000b#\f#\u0322\u0001$\u0001$\u0001%\u0001"+ + "%\u0001&\u0001&\u0001&\u0003&\u032c\b&\u0001\'\u0001\'\u0001(\u0001(\u0001"+ + "(\u0003(\u0333\b(\u0001)\u0001)\u0001)\u0005)\u0338\b)\n)\f)\u033b\t)"+ + "\u0001)\u0001)\u0001)\u0001)\u0001)\u0001)\u0005)\u0343\b)\n)\f)\u0346"+ + "\t)\u0001)\u0001)\u0001)\u0001)\u0001)\u0003)\u034d\b)\u0001)\u0003)\u0350"+ + "\b)\u0003)\u0352\b)\u0001*\u0004*\u0355\b*\u000b*\f*\u0356\u0001+\u0004"+ + "+\u035a\b+\u000b+\f+\u035b\u0001+\u0001+\u0005+\u0360\b+\n+\f+\u0363\t"+ + "+\u0001+\u0001+\u0004+\u0367\b+\u000b+\f+\u0368\u0001+\u0004+\u036c\b"+ + "+\u000b+\f+\u036d\u0001+\u0001+\u0005+\u0372\b+\n+\f+\u0375\t+\u0003+"+ + "\u0377\b+\u0001+\u0001+\u0001+\u0001+\u0004+\u037d\b+\u000b+\f+\u037e"+ + "\u0001+\u0001+\u0003+\u0383\b+\u0001,\u0001,\u0001,\u0001-\u0001-\u0001"+ "-\u0001-\u0001.\u0001.\u0001.\u0001.\u0001/\u0001/\u00010\u00010\u0001"+ "0\u00011\u00011\u00012\u00012\u00013\u00013\u00013\u00013\u00013\u0001"+ "4\u00014\u00015\u00015\u00015\u00015\u00015\u00015\u00016\u00016\u0001"+ "6\u00016\u00016\u00016\u00017\u00017\u00017\u00018\u00018\u00018\u0001"+ "9\u00019\u00019\u00019\u00019\u0001:\u0001:\u0001:\u0001:\u0001:\u0001"+ - ";\u0001;\u0001<\u0001<\u0001<\u0001<\u0001=\u0001=\u0001=\u0001=\u0001"+ - "=\u0001>\u0001>\u0001>\u0001>\u0001>\u0001>\u0001?\u0001?\u0001?\u0001"+ - "@\u0001@\u0001A\u0001A\u0001A\u0001A\u0001A\u0001A\u0001B\u0001B\u0001"+ - "C\u0001C\u0001C\u0001C\u0001C\u0001D\u0001D\u0001D\u0001E\u0001E\u0001"+ - "E\u0001F\u0001F\u0001F\u0001G\u0001G\u0001H\u0001H\u0001H\u0001I\u0001"+ - "I\u0001J\u0001J\u0001J\u0001K\u0001K\u0001L\u0001L\u0001M\u0001M\u0001"+ - "N\u0001N\u0001O\u0001O\u0001P\u0001P\u0001Q\u0001Q\u0001R\u0001R\u0001"+ - "R\u0001R\u0001S\u0001S\u0001S\u0001S\u0001S\u0001T\u0001T\u0001T\u0001"+ - "T\u0001T\u0001U\u0001U\u0001U\u0003U\u0417\bU\u0001U\u0005U\u041a\bU\n"+ - "U\fU\u041d\tU\u0001U\u0001U\u0004U\u0421\bU\u000bU\fU\u0422\u0003U\u0425"+ - "\bU\u0001V\u0001V\u0001V\u0001V\u0001V\u0001W\u0001W\u0001W\u0001W\u0001"+ - "W\u0001X\u0001X\u0005X\u0433\bX\nX\fX\u0436\tX\u0001X\u0001X\u0003X\u043a"+ - "\bX\u0001X\u0004X\u043d\bX\u000bX\fX\u043e\u0003X\u0441\bX\u0001Y\u0001"+ - "Y\u0004Y\u0445\bY\u000bY\fY\u0446\u0001Y\u0001Y\u0001Z\u0001Z\u0001[\u0001"+ - "[\u0001[\u0001[\u0001\\\u0001\\\u0001\\\u0001\\\u0001]\u0001]\u0001]\u0001"+ - "]\u0001^\u0001^\u0001^\u0001^\u0001^\u0001_\u0001_\u0001_\u0001_\u0001"+ - "_\u0001`\u0001`\u0001`\u0001`\u0001a\u0001a\u0001a\u0001a\u0001b\u0001"+ - "b\u0001b\u0001b\u0001c\u0001c\u0001c\u0001c\u0001c\u0001d\u0001d\u0001"+ - "d\u0001d\u0001e\u0001e\u0001e\u0001e\u0001f\u0001f\u0001f\u0001f\u0001"+ - "g\u0001g\u0001g\u0001g\u0001h\u0001h\u0001h\u0001h\u0001i\u0001i\u0001"+ - "i\u0001i\u0001i\u0001i\u0001i\u0001i\u0001i\u0001j\u0001j\u0001j\u0003"+ - "j\u0494\bj\u0001k\u0004k\u0497\bk\u000bk\fk\u0498\u0001l\u0001l\u0001"+ - "l\u0001l\u0001m\u0001m\u0001m\u0001m\u0001n\u0001n\u0001n\u0001n\u0001"+ - "o\u0001o\u0001o\u0001o\u0001p\u0001p\u0001p\u0001p\u0001q\u0001q\u0001"+ - "q\u0001q\u0001q\u0001r\u0001r\u0001r\u0001r\u0001s\u0001s\u0001s\u0001"+ - "s\u0001t\u0001t\u0001t\u0001t\u0001u\u0001u\u0001u\u0001u\u0001v\u0001"+ - "v\u0001v\u0001v\u0003v\u04c8\bv\u0001w\u0001w\u0003w\u04cc\bw\u0001w\u0005"+ - "w\u04cf\bw\nw\fw\u04d2\tw\u0001w\u0001w\u0003w\u04d6\bw\u0001w\u0004w"+ - "\u04d9\bw\u000bw\fw\u04da\u0003w\u04dd\bw\u0001x\u0001x\u0004x\u04e1\b"+ - "x\u000bx\fx\u04e2\u0001y\u0001y\u0001y\u0001y\u0001z\u0001z\u0001z\u0001"+ - "z\u0001{\u0001{\u0001{\u0001{\u0001|\u0001|\u0001|\u0001|\u0001|\u0001"+ - "}\u0001}\u0001}\u0001}\u0001~\u0001~\u0001~\u0001~\u0001\u007f\u0001\u007f"+ - "\u0001\u007f\u0001\u007f\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0080"+ - "\u0001\u0081\u0001\u0081\u0001\u0081\u0001\u0081\u0001\u0082\u0001\u0082"+ - "\u0001\u0082\u0001\u0083\u0001\u0083\u0001\u0083\u0001\u0083\u0001\u0084"+ - "\u0001\u0084\u0001\u0084\u0001\u0084\u0001\u0085\u0001\u0085\u0001\u0085"+ - "\u0001\u0085\u0001\u0086\u0001\u0086\u0001\u0086\u0001\u0086\u0001\u0087"+ + ";\u0001;\u0001;\u0001;\u0001<\u0001<\u0001<\u0001<\u0001<\u0001=\u0001"+ + "=\u0001=\u0001=\u0001=\u0001=\u0001>\u0001>\u0001>\u0001?\u0001?\u0001"+ + "@\u0001@\u0001@\u0001@\u0001@\u0001@\u0001A\u0001A\u0001A\u0001A\u0001"+ + "A\u0001B\u0001B\u0001B\u0001C\u0001C\u0001C\u0001D\u0001D\u0001D\u0001"+ + "E\u0001E\u0001F\u0001F\u0001F\u0001G\u0001G\u0001H\u0001H\u0001H\u0001"+ + "I\u0001I\u0001J\u0001J\u0001K\u0001K\u0001L\u0001L\u0001M\u0001M\u0001"+ + "N\u0001N\u0001O\u0001O\u0001P\u0001P\u0001P\u0001P\u0001Q\u0001Q\u0001"+ + "Q\u0003Q\u0403\bQ\u0001Q\u0005Q\u0406\bQ\nQ\fQ\u0409\tQ\u0001Q\u0001Q"+ + "\u0004Q\u040d\bQ\u000bQ\fQ\u040e\u0003Q\u0411\bQ\u0001R\u0001R\u0001R"+ + "\u0001R\u0001R\u0001S\u0001S\u0001S\u0001S\u0001S\u0001T\u0001T\u0001"+ + "T\u0001T\u0001T\u0001U\u0001U\u0001U\u0001U\u0001U\u0001V\u0001V\u0005"+ + "V\u0429\bV\nV\fV\u042c\tV\u0001V\u0001V\u0003V\u0430\bV\u0001V\u0004V"+ + "\u0433\bV\u000bV\fV\u0434\u0003V\u0437\bV\u0001W\u0001W\u0004W\u043b\b"+ + "W\u000bW\fW\u043c\u0001W\u0001W\u0001X\u0001X\u0001Y\u0001Y\u0001Y\u0001"+ + "Y\u0001Z\u0001Z\u0001Z\u0001Z\u0001[\u0001[\u0001[\u0001[\u0001\\\u0001"+ + "\\\u0001\\\u0001\\\u0001\\\u0001]\u0001]\u0001]\u0001]\u0001]\u0001^\u0001"+ + "^\u0001^\u0001^\u0001_\u0001_\u0001_\u0001_\u0001`\u0001`\u0001`\u0001"+ + "`\u0001a\u0001a\u0001a\u0001a\u0001a\u0001b\u0001b\u0001b\u0001b\u0001"+ + "c\u0001c\u0001c\u0001c\u0001d\u0001d\u0001d\u0001d\u0001e\u0001e\u0001"+ + "e\u0001e\u0001f\u0001f\u0001f\u0001f\u0001g\u0001g\u0001g\u0001g\u0001"+ + "g\u0001g\u0001g\u0001g\u0001g\u0001h\u0001h\u0001h\u0003h\u048a\bh\u0001"+ + "i\u0004i\u048d\bi\u000bi\fi\u048e\u0001j\u0001j\u0001j\u0001j\u0001k\u0001"+ + "k\u0001k\u0001k\u0001l\u0001l\u0001l\u0001l\u0001m\u0001m\u0001m\u0001"+ + "m\u0001n\u0001n\u0001n\u0001n\u0001o\u0001o\u0001o\u0001o\u0001o\u0001"+ + "p\u0001p\u0001p\u0001p\u0001q\u0001q\u0001q\u0001q\u0001r\u0001r\u0001"+ + "r\u0001r\u0001s\u0001s\u0001s\u0001s\u0001t\u0001t\u0001t\u0001t\u0003"+ + "t\u04be\bt\u0001u\u0001u\u0003u\u04c2\bu\u0001u\u0005u\u04c5\bu\nu\fu"+ + "\u04c8\tu\u0001u\u0001u\u0003u\u04cc\bu\u0001u\u0004u\u04cf\bu\u000bu"+ + "\fu\u04d0\u0003u\u04d3\bu\u0001v\u0001v\u0004v\u04d7\bv\u000bv\fv\u04d8"+ + "\u0001w\u0001w\u0001w\u0001w\u0001x\u0001x\u0001x\u0001x\u0001y\u0001"+ + "y\u0001y\u0001y\u0001z\u0001z\u0001z\u0001z\u0001z\u0001{\u0001{\u0001"+ + "{\u0001{\u0001|\u0001|\u0001|\u0001|\u0001}\u0001}\u0001}\u0001}\u0001"+ + "~\u0001~\u0001~\u0001~\u0001\u007f\u0001\u007f\u0001\u007f\u0001\u007f"+ + "\u0001\u0080\u0001\u0080\u0001\u0080\u0001\u0081\u0001\u0081\u0001\u0081"+ + "\u0001\u0081\u0001\u0082\u0001\u0082\u0001\u0082\u0001\u0082\u0001\u0083"+ + "\u0001\u0083\u0001\u0083\u0001\u0083\u0001\u0084\u0001\u0084\u0001\u0084"+ + "\u0001\u0084\u0001\u0085\u0001\u0085\u0001\u0085\u0001\u0085\u0001\u0085"+ + "\u0001\u0086\u0001\u0086\u0001\u0086\u0001\u0086\u0001\u0086\u0001\u0087"+ "\u0001\u0087\u0001\u0087\u0001\u0087\u0001\u0087\u0001\u0088\u0001\u0088"+ - "\u0001\u0088\u0001\u0088\u0001\u0088\u0001\u0089\u0001\u0089\u0001\u0089"+ - "\u0001\u0089\u0001\u0089\u0001\u008a\u0001\u008a\u0001\u008a\u0001\u008a"+ - "\u0001\u008a\u0001\u008a\u0001\u008a\u0001\u008b\u0001\u008b\u0001\u008c"+ - "\u0004\u008c\u0536\b\u008c\u000b\u008c\f\u008c\u0537\u0001\u008c\u0001"+ - "\u008c\u0003\u008c\u053c\b\u008c\u0001\u008c\u0004\u008c\u053f\b\u008c"+ - "\u000b\u008c\f\u008c\u0540\u0001\u008d\u0001\u008d\u0001\u008d\u0001\u008d"+ - "\u0001\u008e\u0001\u008e\u0001\u008e\u0001\u008e\u0001\u008f\u0001\u008f"+ + "\u0001\u0088\u0001\u0088\u0001\u0088\u0001\u0088\u0001\u0088\u0001\u0089"+ + "\u0001\u0089\u0001\u008a\u0004\u008a\u052c\b\u008a\u000b\u008a\f\u008a"+ + "\u052d\u0001\u008a\u0001\u008a\u0003\u008a\u0532\b\u008a\u0001\u008a\u0004"+ + "\u008a\u0535\b\u008a\u000b\u008a\f\u008a\u0536\u0001\u008b\u0001\u008b"+ + "\u0001\u008b\u0001\u008b\u0001\u008c\u0001\u008c\u0001\u008c\u0001\u008c"+ + "\u0001\u008d\u0001\u008d\u0001\u008d\u0001\u008d\u0001\u008e\u0001\u008e"+ + "\u0001\u008e\u0001\u008e\u0001\u008f\u0001\u008f\u0001\u008f\u0001\u008f"+ "\u0001\u008f\u0001\u008f\u0001\u0090\u0001\u0090\u0001\u0090\u0001\u0090"+ - "\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0091"+ - "\u0001\u0092\u0001\u0092\u0001\u0092\u0001\u0092\u0001\u0093\u0001\u0093"+ - "\u0001\u0093\u0001\u0093\u0001\u0094\u0001\u0094\u0001\u0094\u0001\u0094"+ - "\u0001\u0095\u0001\u0095\u0001\u0095\u0001\u0095\u0001\u0096\u0001\u0096"+ - "\u0001\u0096\u0001\u0096\u0001\u0097\u0001\u0097\u0001\u0097\u0001\u0097"+ - "\u0001\u0098\u0001\u0098\u0001\u0098\u0001\u0098\u0001\u0099\u0001\u0099"+ - "\u0001\u0099\u0001\u0099\u0001\u009a\u0001\u009a\u0001\u009a\u0001\u009a"+ - "\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009c\u0001\u009c"+ - "\u0001\u009c\u0001\u009c\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009d"+ - "\u0001\u009d\u0001\u009e\u0001\u009e\u0001\u009e\u0001\u009e\u0001\u009f"+ - "\u0001\u009f\u0001\u009f\u0001\u009f\u0001\u00a0\u0001\u00a0\u0001\u00a0"+ - "\u0001\u00a0\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a2"+ - "\u0001\u00a2\u0001\u00a2\u0001\u00a2\u0001\u00a3\u0001\u00a3\u0001\u00a3"+ - "\u0001\u00a3\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001\u00a5"+ + "\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0091\u0001\u0092\u0001\u0092"+ + "\u0001\u0092\u0001\u0092\u0001\u0093\u0001\u0093\u0001\u0093\u0001\u0093"+ + "\u0001\u0094\u0001\u0094\u0001\u0094\u0001\u0094\u0001\u0095\u0001\u0095"+ + "\u0001\u0095\u0001\u0095\u0001\u0096\u0001\u0096\u0001\u0096\u0001\u0096"+ + "\u0001\u0097\u0001\u0097\u0001\u0097\u0001\u0097\u0001\u0098\u0001\u0098"+ + "\u0001\u0098\u0001\u0098\u0001\u0099\u0001\u0099\u0001\u0099\u0001\u0099"+ + "\u0001\u009a\u0001\u009a\u0001\u009a\u0001\u009a\u0001\u009b\u0001\u009b"+ + "\u0001\u009b\u0001\u009b\u0001\u009b\u0001\u009c\u0001\u009c\u0001\u009c"+ + "\u0001\u009c\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009d\u0001\u009e"+ + "\u0001\u009e\u0001\u009e\u0001\u009e\u0001\u009f\u0001\u009f\u0001\u009f"+ + "\u0001\u009f\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a0\u0001\u00a1"+ + "\u0001\u00a1\u0001\u00a1\u0001\u00a1\u0001\u00a2\u0001\u00a2\u0001\u00a2"+ + "\u0001\u00a2\u0001\u00a3\u0001\u00a3\u0001\u00a3\u0001\u00a3\u0001\u00a4"+ + "\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001\u00a4\u0001\u00a5\u0001\u00a5"+ "\u0001\u00a5\u0001\u00a5\u0001\u00a5\u0001\u00a6\u0001\u00a6\u0001\u00a6"+ - "\u0001\u00a6\u0001\u00a6\u0001\u00a7\u0001\u00a7\u0001\u00a7\u0001\u00a7"+ - "\u0001\u00a7\u0001\u00a8\u0001\u00a8\u0001\u00a8\u0001\u00a8\u0001\u00a9"+ - "\u0001\u00a9\u0001\u00a9\u0001\u00a9\u0001\u00aa\u0001\u00aa\u0001\u00aa"+ - "\u0001\u00aa\u0001\u00ab\u0001\u00ab\u0001\u00ab\u0001\u00ab\u0001\u00ab"+ - "\u0001\u00ac\u0001\u00ac\u0001\u00ac\u0001\u00ac\u0001\u00ad\u0001\u00ad"+ - "\u0001\u00ad\u0001\u00ad\u0001\u00ad\u0004\u00ad\u05ce\b\u00ad\u000b\u00ad"+ - "\f\u00ad\u05cf\u0001\u00ae\u0001\u00ae\u0001\u00ae\u0001\u00ae\u0001\u00af"+ - "\u0001\u00af\u0001\u00af\u0001\u00af\u0001\u00b0\u0001\u00b0\u0001\u00b0"+ - "\u0001\u00b0\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001\u00b1"+ - "\u0001\u00b2\u0001\u00b2\u0001\u00b2\u0001\u00b2\u0001\u00b3\u0001\u00b3"+ - "\u0001\u00b3\u0001\u00b3\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4"+ - "\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b6"+ - "\u0001\u00b6\u0001\u00b6\u0001\u00b6\u0001\u00b7\u0001\u00b7\u0001\u00b7"+ - "\u0001\u00b7\u0001\u00b8\u0001\u00b8\u0001\u00b8\u0001\u00b8\u0001\u00b9"+ - "\u0001\u00b9\u0001\u00b9\u0001\u00b9\u0001\u00ba\u0001\u00ba\u0001\u00ba"+ - "\u0001\u00ba\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001\u00bb"+ - "\u0001\u00bb\u0001\u00bc\u0001\u00bc\u0001\u00bc\u0001\u00bc\u0001\u00bd"+ - "\u0001\u00bd\u0001\u00bd\u0001\u00bd\u0001\u00be\u0001\u00be\u0001\u00be"+ - "\u0001\u00be\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00c0"+ - "\u0001\u00c0\u0001\u00c0\u0001\u00c0\u0001\u00c1\u0001\u00c1\u0001\u00c1"+ - "\u0001\u00c1\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c2"+ - "\u0001\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c4"+ - "\u0001\u00c4\u0001\u00c4\u0001\u00c4\u0001\u00c5\u0001\u00c5\u0001\u00c5"+ - "\u0001\u00c5\u0001\u00c5\u0001\u00c5\u0001\u00c6\u0001\u00c6\u0001\u00c6"+ - "\u0001\u00c6\u0001\u00c6\u0001\u00c6\u0001\u00c6\u0001\u00c6\u0001\u00c6"+ - "\u0001\u00c7\u0001\u00c7\u0001\u00c7\u0001\u00c7\u0001\u00c8\u0001\u00c8"+ - "\u0001\u00c8\u0001\u00c8\u0001\u00c9\u0001\u00c9\u0001\u00c9\u0001\u00c9"+ - "\u0001\u00ca\u0001\u00ca\u0001\u00ca\u0001\u00ca\u0001\u00cb\u0001\u00cb"+ - "\u0001\u00cb\u0001\u00cb\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001\u00cc"+ - "\u0001\u00cd\u0001\u00cd\u0001\u00cd\u0001\u00cd\u0001\u00ce\u0001\u00ce"+ - "\u0001\u00ce\u0001\u00ce\u0001\u00cf\u0001\u00cf\u0001\u00cf\u0001\u00cf"+ - "\u0001\u00cf\u0001\u00d0\u0001\u00d0\u0001\u00d0\u0001\u00d0\u0001\u00d0"+ - "\u0001\u00d0\u0001\u00d1\u0001\u00d1\u0001\u00d1\u0001\u00d1\u0001\u00d1"+ - "\u0001\u00d1\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d3"+ - "\u0001\u00d3\u0001\u00d3\u0001\u00d3\u0001\u00d4\u0001\u00d4\u0001\u00d4"+ - "\u0001\u00d4\u0001\u00d5\u0001\u00d5\u0001\u00d5\u0001\u00d5\u0001\u00d5"+ - "\u0001\u00d5\u0001\u00d6\u0001\u00d6\u0001\u00d6\u0001\u00d6\u0001\u00d6"+ - "\u0001\u00d6\u0001\u00d7\u0001\u00d7\u0001\u00d7\u0001\u00d7\u0001\u00d8"+ - "\u0001\u00d8\u0001\u00d8\u0001\u00d8\u0001\u00d9\u0001\u00d9\u0001\u00d9"+ - "\u0001\u00d9\u0001\u00da\u0001\u00da\u0001\u00da\u0001\u00da\u0001\u00da"+ - "\u0001\u00da\u0001\u00db\u0001\u00db\u0001\u00db\u0001\u00db\u0001\u00db"+ - "\u0001\u00db\u0001\u00dc\u0001\u00dc\u0001\u00dc\u0001\u00dc\u0001\u00dc"+ - "\u0001\u00dc\u0001\u00dd\u0001\u00dd\u0001\u00dd\u0001\u00dd\u0001\u00dd"+ - "\u0001\u00de\u0001\u00de\u0001\u00de\u0001\u00de\u0001\u00de\u0001\u00df"+ - "\u0001\u00df\u0001\u00df\u0001\u00df\u0001\u00e0\u0001\u00e0\u0001\u00e0"+ - "\u0001\u00e0\u0001\u00e1\u0001\u00e1\u0001\u00e1\u0001\u00e1\u0001\u00e2"+ - "\u0001\u00e2\u0001\u00e2\u0001\u00e2\u0001\u00e3\u0001\u00e3\u0001\u00e3"+ - "\u0001\u00e3\u0001\u00e4\u0001\u00e4\u0001\u00e4\u0001\u00e4\u0001\u00e5"+ - "\u0001\u00e5\u0001\u00e5\u0001\u00e5\u0001\u00e6\u0001\u00e6\u0001\u00e6"+ - "\u0001\u00e6\u0001\u00e7\u0001\u00e7\u0001\u00e7\u0001\u00e7\u0001\u00e8"+ - "\u0001\u00e8\u0001\u00e8\u0001\u00e8\u0001\u00e8\u0001\u00e9\u0001\u00e9"+ - "\u0001\u00e9\u0001\u00e9\u0001\u00ea\u0001\u00ea\u0001\u00ea\u0001\u00ea"+ - "\u0001\u00eb\u0001\u00eb\u0001\u00eb\u0001\u00eb\u0001\u00ec\u0001\u00ec"+ - "\u0001\u00ec\u0001\u00ec\u0001\u00ed\u0001\u00ed\u0001\u00ed\u0001\u00ed"+ - "\u0001\u00ed\u0001\u00ee\u0001\u00ee\u0001\u00ee\u0001\u00ee\u0001\u00ee"+ - "\u0001\u00ef\u0001\u00ef\u0001\u00ef\u0001\u00ef\u0001\u00ef\u0001\u00f0"+ - "\u0001\u00f0\u0001\u00f0\u0001\u00f0\u0001\u00f1\u0001\u00f1\u0001\u00f1"+ - "\u0001\u00f1\u0001\u00f2\u0001\u00f2\u0001\u00f2\u0001\u00f2\u0002\u0305"+ - "\u034a\u0000\u00f3\u0013\u0001\u0015\u0002\u0017\u0003\u0019\u0004\u001b"+ - "\u0005\u001d\u0006\u001f\u0007!\b#\t%\n\'\u000b)\f+\r-\u000e/\u000f1\u0010"+ - "3\u00115\u00127\u00139\u0014;\u0015=\u0016?\u0017A\u0018C\u0019E\u001a"+ - "G\u001bI\u001cK\u001dM\u001eO\u001fQ\u0000S\u0000U\u0000W\u0000Y\u0000"+ - "[\u0000]\u0000_\u0000a\u0000c\u0000e g!i\"k#m$o%q&s\'u(w)y*{+},\u007f"+ - "-\u0081.\u0083/\u00850\u00871\u00892\u008b3\u008d4\u008f5\u00916\u0093"+ - "7\u00958\u00979\u0099:\u009b;\u009d<\u009f=\u00a1>\u00a3?\u00a5@\u00a7"+ - "A\u00a9B\u00abC\u00adD\u00afE\u00b1F\u00b3G\u00b5H\u00b7\u0000\u00b9\u0000"+ - "\u00bb\u0000\u00bdI\u00bfJ\u00c1K\u00c3L\u00c5\u0000\u00c7M\u00c9N\u00cb"+ - "O\u00cdP\u00cf\u0000\u00d1\u0000\u00d3Q\u00d5R\u00d7S\u00d9\u0000\u00db"+ - "\u0000\u00dd\u0000\u00df\u0000\u00e1\u0000\u00e3\u0000\u00e5T\u00e7\u0000"+ - "\u00e9U\u00eb\u0000\u00ed\u0000\u00efV\u00f1W\u00f3X\u00f5\u0000\u00f7"+ - "\u0000\u00f9\u0000\u00fb\u0000\u00fd\u0000\u00ff\u0000\u0101\u0000\u0103"+ - "Y\u0105Z\u0107[\u0109\\\u010b\u0000\u010d\u0000\u010f\u0000\u0111\u0000"+ - "\u0113\u0000\u0115\u0000\u0117]\u0119\u0000\u011b^\u011d_\u011f`\u0121"+ - "\u0000\u0123\u0000\u0125a\u0127b\u0129\u0000\u012bc\u012d\u0000\u012f"+ - "d\u0131e\u0133f\u0135\u0000\u0137\u0000\u0139\u0000\u013b\u0000\u013d"+ - "\u0000\u013f\u0000\u0141\u0000\u0143\u0000\u0145\u0000\u0147g\u0149h\u014b"+ - "i\u014d\u0000\u014f\u0000\u0151\u0000\u0153\u0000\u0155\u0000\u0157\u0000"+ - "\u0159j\u015bk\u015dl\u015f\u0000\u0161m\u0163n\u0165o\u0167p\u0169\u0000"+ - "\u016b\u0000\u016dq\u016fr\u0171s\u0173t\u0175\u0000\u0177\u0000\u0179"+ - "\u0000\u017b\u0000\u017d\u0000\u017f\u0000\u0181\u0000\u0183u\u0185v\u0187"+ - "w\u0189\u0000\u018b\u0000\u018d\u0000\u018f\u0000\u0191x\u0193y\u0195"+ - "z\u0197\u0000\u0199{\u019b\u0000\u019d\u0000\u019f|\u01a1\u0000\u01a3"+ - "\u0000\u01a5\u0000\u01a7\u0000\u01a9\u0000\u01ab}\u01ad~\u01af\u007f\u01b1"+ - "\u0000\u01b3\u0000\u01b5\u0000\u01b7\u0080\u01b9\u0081\u01bb\u0082\u01bd"+ - "\u0000\u01bf\u0000\u01c1\u0083\u01c3\u0084\u01c5\u0085\u01c7\u0000\u01c9"+ - "\u0000\u01cb\u0000\u01cd\u0000\u01cf\u0000\u01d1\u0000\u01d3\u0000\u01d5"+ - "\u0000\u01d7\u0000\u01d9\u0000\u01db\u0000\u01dd\u0086\u01df\u0087\u01e1"+ - "\u0088\u01e3\u0000\u01e5\u0000\u01e7\u0089\u01e9\u008a\u01eb\u008b\u01ed"+ - "\u0000\u01ef\u0000\u01f1\u0000\u01f3\u008c\u01f5\u008d\u01f7\u008e\u0013"+ - "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e"+ - "\u000f\u0010\u0011\u0012$\u0002\u0000DDdd\u0002\u0000IIii\u0002\u0000"+ - "SSss\u0002\u0000EEee\u0002\u0000CCcc\u0002\u0000TTtt\u0002\u0000RRrr\u0002"+ - "\u0000OOoo\u0002\u0000PPpp\u0002\u0000NNnn\u0002\u0000HHhh\u0002\u0000"+ - "VVvv\u0002\u0000AAaa\u0002\u0000LLll\u0002\u0000XXxx\u0002\u0000FFff\u0002"+ - "\u0000MMmm\u0002\u0000GGgg\u0002\u0000KKkk\u0002\u0000WWww\u0002\u0000"+ - "UUuu\u0006\u0000\t\n\r\r //[[]]\u0002\u0000\n\n\r\r\u0003\u0000\t\n\r"+ - "\r \u0001\u000009\u0002\u0000AZaz\b\u0000\"\"NNRRTT\\\\nnrrtt\u0004\u0000"+ - "\n\n\r\r\"\"\\\\\u0002\u0000++--\u0001\u0000``\u0002\u0000BBbb\u0002\u0000"+ - "YYyy\u000b\u0000\t\n\r\r \"\",,//::==[[]]||\u0002\u0000**//\u000b\u0000"+ - "\t\n\r\r \"#,,//::<<>?\\\\||\u0002\u0000JJjj\u071f\u0000\u0013\u0001"+ - "\u0000\u0000\u0000\u0000\u0015\u0001\u0000\u0000\u0000\u0000\u0017\u0001"+ - "\u0000\u0000\u0000\u0000\u0019\u0001\u0000\u0000\u0000\u0000\u001b\u0001"+ - "\u0000\u0000\u0000\u0000\u001d\u0001\u0000\u0000\u0000\u0000\u001f\u0001"+ - "\u0000\u0000\u0000\u0000!\u0001\u0000\u0000\u0000\u0000#\u0001\u0000\u0000"+ - "\u0000\u0000%\u0001\u0000\u0000\u0000\u0000\'\u0001\u0000\u0000\u0000"+ - "\u0000)\u0001\u0000\u0000\u0000\u0000+\u0001\u0000\u0000\u0000\u0000-"+ - "\u0001\u0000\u0000\u0000\u0000/\u0001\u0000\u0000\u0000\u00001\u0001\u0000"+ - "\u0000\u0000\u00003\u0001\u0000\u0000\u0000\u00005\u0001\u0000\u0000\u0000"+ - "\u00007\u0001\u0000\u0000\u0000\u00009\u0001\u0000\u0000\u0000\u0000;"+ - "\u0001\u0000\u0000\u0000\u0000=\u0001\u0000\u0000\u0000\u0000?\u0001\u0000"+ - "\u0000\u0000\u0000A\u0001\u0000\u0000\u0000\u0000C\u0001\u0000\u0000\u0000"+ - "\u0000E\u0001\u0000\u0000\u0000\u0000G\u0001\u0000\u0000\u0000\u0000I"+ - "\u0001\u0000\u0000\u0000\u0000K\u0001\u0000\u0000\u0000\u0000M\u0001\u0000"+ - "\u0000\u0000\u0001O\u0001\u0000\u0000\u0000\u0001e\u0001\u0000\u0000\u0000"+ - "\u0001g\u0001\u0000\u0000\u0000\u0001i\u0001\u0000\u0000\u0000\u0001k"+ - "\u0001\u0000\u0000\u0000\u0001m\u0001\u0000\u0000\u0000\u0001o\u0001\u0000"+ - "\u0000\u0000\u0001q\u0001\u0000\u0000\u0000\u0001s\u0001\u0000\u0000\u0000"+ - "\u0001u\u0001\u0000\u0000\u0000\u0001w\u0001\u0000\u0000\u0000\u0001y"+ - "\u0001\u0000\u0000\u0000\u0001{\u0001\u0000\u0000\u0000\u0001}\u0001\u0000"+ - "\u0000\u0000\u0001\u007f\u0001\u0000\u0000\u0000\u0001\u0081\u0001\u0000"+ - "\u0000\u0000\u0001\u0083\u0001\u0000\u0000\u0000\u0001\u0085\u0001\u0000"+ - "\u0000\u0000\u0001\u0087\u0001\u0000\u0000\u0000\u0001\u0089\u0001\u0000"+ - "\u0000\u0000\u0001\u008b\u0001\u0000\u0000\u0000\u0001\u008d\u0001\u0000"+ - "\u0000\u0000\u0001\u008f\u0001\u0000\u0000\u0000\u0001\u0091\u0001\u0000"+ - "\u0000\u0000\u0001\u0093\u0001\u0000\u0000\u0000\u0001\u0095\u0001\u0000"+ - "\u0000\u0000\u0001\u0097\u0001\u0000\u0000\u0000\u0001\u0099\u0001\u0000"+ - "\u0000\u0000\u0001\u009b\u0001\u0000\u0000\u0000\u0001\u009d\u0001\u0000"+ - "\u0000\u0000\u0001\u009f\u0001\u0000\u0000\u0000\u0001\u00a1\u0001\u0000"+ - "\u0000\u0000\u0001\u00a3\u0001\u0000\u0000\u0000\u0001\u00a5\u0001\u0000"+ - "\u0000\u0000\u0001\u00a7\u0001\u0000\u0000\u0000\u0001\u00a9\u0001\u0000"+ - "\u0000\u0000\u0001\u00ab\u0001\u0000\u0000\u0000\u0001\u00ad\u0001\u0000"+ - "\u0000\u0000\u0001\u00af\u0001\u0000\u0000\u0000\u0001\u00b1\u0001\u0000"+ - "\u0000\u0000\u0001\u00b3\u0001\u0000\u0000\u0000\u0001\u00b5\u0001\u0000"+ - "\u0000\u0000\u0001\u00b7\u0001\u0000\u0000\u0000\u0001\u00b9\u0001\u0000"+ - "\u0000\u0000\u0001\u00bb\u0001\u0000\u0000\u0000\u0001\u00bd\u0001\u0000"+ - "\u0000\u0000\u0001\u00bf\u0001\u0000\u0000\u0000\u0001\u00c1\u0001\u0000"+ - "\u0000\u0000\u0001\u00c3\u0001\u0000\u0000\u0000\u0001\u00c7\u0001\u0000"+ - "\u0000\u0000\u0001\u00c9\u0001\u0000\u0000\u0000\u0001\u00cb\u0001\u0000"+ - "\u0000\u0000\u0001\u00cd\u0001\u0000\u0000\u0000\u0002\u00cf\u0001\u0000"+ - "\u0000\u0000\u0002\u00d1\u0001\u0000\u0000\u0000\u0002\u00d3\u0001\u0000"+ - "\u0000\u0000\u0002\u00d5\u0001\u0000\u0000\u0000\u0002\u00d7\u0001\u0000"+ - "\u0000\u0000\u0003\u00d9\u0001\u0000\u0000\u0000\u0003\u00db\u0001\u0000"+ - "\u0000\u0000\u0003\u00dd\u0001\u0000\u0000\u0000\u0003\u00df\u0001\u0000"+ - "\u0000\u0000\u0003\u00e1\u0001\u0000\u0000\u0000\u0003\u00e3\u0001\u0000"+ - "\u0000\u0000\u0003\u00e5\u0001\u0000\u0000\u0000\u0003\u00e9\u0001\u0000"+ - "\u0000\u0000\u0003\u00eb\u0001\u0000\u0000\u0000\u0003\u00ed\u0001\u0000"+ - "\u0000\u0000\u0003\u00ef\u0001\u0000\u0000\u0000\u0003\u00f1\u0001\u0000"+ - "\u0000\u0000\u0003\u00f3\u0001\u0000\u0000\u0000\u0004\u00f5\u0001\u0000"+ - "\u0000\u0000\u0004\u00f7\u0001\u0000\u0000\u0000\u0004\u00f9\u0001\u0000"+ - "\u0000\u0000\u0004\u00fb\u0001\u0000\u0000\u0000\u0004\u00fd\u0001\u0000"+ - "\u0000\u0000\u0004\u0103\u0001\u0000\u0000\u0000\u0004\u0105\u0001\u0000"+ - "\u0000\u0000\u0004\u0107\u0001\u0000\u0000\u0000\u0004\u0109\u0001\u0000"+ - "\u0000\u0000\u0005\u010b\u0001\u0000\u0000\u0000\u0005\u010d\u0001\u0000"+ - "\u0000\u0000\u0005\u010f\u0001\u0000\u0000\u0000\u0005\u0111\u0001\u0000"+ - "\u0000\u0000\u0005\u0113\u0001\u0000\u0000\u0000\u0005\u0115\u0001\u0000"+ - "\u0000\u0000\u0005\u0117\u0001\u0000\u0000\u0000\u0005\u0119\u0001\u0000"+ - "\u0000\u0000\u0005\u011b\u0001\u0000\u0000\u0000\u0005\u011d\u0001\u0000"+ - "\u0000\u0000\u0005\u011f\u0001\u0000\u0000\u0000\u0006\u0121\u0001\u0000"+ - "\u0000\u0000\u0006\u0123\u0001\u0000\u0000\u0000\u0006\u0125\u0001\u0000"+ - "\u0000\u0000\u0006\u0127\u0001\u0000\u0000\u0000\u0006\u012b\u0001\u0000"+ - "\u0000\u0000\u0006\u012d\u0001\u0000\u0000\u0000\u0006\u012f\u0001\u0000"+ - "\u0000\u0000\u0006\u0131\u0001\u0000\u0000\u0000\u0006\u0133\u0001\u0000"+ - "\u0000\u0000\u0007\u0135\u0001\u0000\u0000\u0000\u0007\u0137\u0001\u0000"+ - "\u0000\u0000\u0007\u0139\u0001\u0000\u0000\u0000\u0007\u013b\u0001\u0000"+ - "\u0000\u0000\u0007\u013d\u0001\u0000\u0000\u0000\u0007\u013f\u0001\u0000"+ - "\u0000\u0000\u0007\u0141\u0001\u0000\u0000\u0000\u0007\u0143\u0001\u0000"+ - "\u0000\u0000\u0007\u0145\u0001\u0000\u0000\u0000\u0007\u0147\u0001\u0000"+ - "\u0000\u0000\u0007\u0149\u0001\u0000\u0000\u0000\u0007\u014b\u0001\u0000"+ + "\u0001\u00a6\u0001\u00a7\u0001\u00a7\u0001\u00a7\u0001\u00a7\u0001\u00a8"+ + "\u0001\u00a8\u0001\u00a8\u0001\u00a8\u0001\u00a9\u0001\u00a9\u0001\u00a9"+ + "\u0001\u00a9\u0001\u00a9\u0001\u00aa\u0001\u00aa\u0001\u00aa\u0001\u00aa"+ + "\u0001\u00ab\u0001\u00ab\u0001\u00ab\u0001\u00ab\u0001\u00ab\u0004\u00ab"+ + "\u05c4\b\u00ab\u000b\u00ab\f\u00ab\u05c5\u0001\u00ac\u0001\u00ac\u0001"+ + "\u00ac\u0001\u00ac\u0001\u00ad\u0001\u00ad\u0001\u00ad\u0001\u00ad\u0001"+ + "\u00ae\u0001\u00ae\u0001\u00ae\u0001\u00ae\u0001\u00af\u0001\u00af\u0001"+ + "\u00af\u0001\u00af\u0001\u00af\u0001\u00b0\u0001\u00b0\u0001\u00b0\u0001"+ + "\u00b0\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001\u00b1\u0001\u00b2\u0001"+ + "\u00b2\u0001\u00b2\u0001\u00b2\u0001\u00b3\u0001\u00b3\u0001\u00b3\u0001"+ + "\u00b3\u0001\u00b3\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001\u00b4\u0001"+ + "\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b5\u0001\u00b6\u0001\u00b6\u0001"+ + "\u00b6\u0001\u00b6\u0001\u00b7\u0001\u00b7\u0001\u00b7\u0001\u00b7\u0001"+ + "\u00b8\u0001\u00b8\u0001\u00b8\u0001\u00b8\u0001\u00b9\u0001\u00b9\u0001"+ + "\u00b9\u0001\u00b9\u0001\u00b9\u0001\u00b9\u0001\u00ba\u0001\u00ba\u0001"+ + "\u00ba\u0001\u00ba\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001\u00bb\u0001"+ + "\u00bc\u0001\u00bc\u0001\u00bc\u0001\u00bc\u0001\u00bd\u0001\u00bd\u0001"+ + "\u00bd\u0001\u00bd\u0001\u00be\u0001\u00be\u0001\u00be\u0001\u00be\u0001"+ + "\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00bf\u0001\u00c0\u0001\u00c0\u0001"+ + "\u00c0\u0001\u00c0\u0001\u00c0\u0001\u00c1\u0001\u00c1\u0001\u00c1\u0001"+ + "\u00c1\u0001\u00c1\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001\u00c2\u0001"+ + "\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c3\u0001\u00c3\u0001"+ + "\u00c4\u0001\u00c4\u0001\u00c4\u0001\u00c4\u0001\u00c4\u0001\u00c4\u0001"+ + "\u00c4\u0001\u00c4\u0001\u00c4\u0001\u00c5\u0001\u00c5\u0001\u00c5\u0001"+ + "\u00c5\u0001\u00c6\u0001\u00c6\u0001\u00c6\u0001\u00c6\u0001\u00c7\u0001"+ + "\u00c7\u0001\u00c7\u0001\u00c7\u0001\u00c8\u0001\u00c8\u0001\u00c8\u0001"+ + "\u00c8\u0001\u00c9\u0001\u00c9\u0001\u00c9\u0001\u00c9\u0001\u00ca\u0001"+ + "\u00ca\u0001\u00ca\u0001\u00ca\u0001\u00cb\u0001\u00cb\u0001\u00cb\u0001"+ + "\u00cb\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001\u00cc\u0001\u00cd\u0001"+ + "\u00cd\u0001\u00cd\u0001\u00cd\u0001\u00cd\u0001\u00ce\u0001\u00ce\u0001"+ + "\u00ce\u0001\u00ce\u0001\u00ce\u0001\u00ce\u0001\u00cf\u0001\u00cf\u0001"+ + "\u00cf\u0001\u00cf\u0001\u00cf\u0001\u00cf\u0001\u00d0\u0001\u00d0\u0001"+ + "\u00d0\u0001\u00d0\u0001\u00d1\u0001\u00d1\u0001\u00d1\u0001\u00d1\u0001"+ + "\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d2\u0001\u00d3\u0001\u00d3\u0001"+ + "\u00d3\u0001\u00d3\u0001\u00d3\u0001\u00d3\u0001\u00d4\u0001\u00d4\u0001"+ + "\u00d4\u0001\u00d4\u0001\u00d4\u0001\u00d4\u0001\u00d5\u0001\u00d5\u0001"+ + "\u00d5\u0001\u00d5\u0001\u00d6\u0001\u00d6\u0001\u00d6\u0001\u00d6\u0001"+ + "\u00d7\u0001\u00d7\u0001\u00d7\u0001\u00d7\u0001\u00d8\u0001\u00d8\u0001"+ + "\u00d8\u0001\u00d8\u0001\u00d8\u0001\u00d8\u0001\u00d9\u0001\u00d9\u0001"+ + "\u00d9\u0001\u00d9\u0001\u00d9\u0001\u00d9\u0001\u00da\u0001\u00da\u0001"+ + "\u00da\u0001\u00da\u0001\u00da\u0001\u00da\u0001\u00db\u0001\u00db\u0001"+ + "\u00db\u0001\u00db\u0001\u00db\u0001\u00dc\u0001\u00dc\u0001\u00dc\u0001"+ + "\u00dc\u0001\u00dc\u0001\u00dd\u0001\u00dd\u0001\u00dd\u0001\u00dd\u0001"+ + "\u00de\u0001\u00de\u0001\u00de\u0001\u00de\u0001\u00df\u0001\u00df\u0001"+ + "\u00df\u0001\u00df\u0001\u00e0\u0001\u00e0\u0001\u00e0\u0001\u00e0\u0001"+ + "\u00e1\u0001\u00e1\u0001\u00e1\u0001\u00e1\u0001\u00e2\u0001\u00e2\u0001"+ + "\u00e2\u0001\u00e2\u0001\u00e3\u0001\u00e3\u0001\u00e3\u0001\u00e3\u0001"+ + "\u00e4\u0001\u00e4\u0001\u00e4\u0001\u00e4\u0001\u00e5\u0001\u00e5\u0001"+ + "\u00e5\u0001\u00e5\u0001\u00e6\u0001\u00e6\u0001\u00e6\u0001\u00e6\u0001"+ + "\u00e6\u0001\u00e7\u0001\u00e7\u0001\u00e7\u0001\u00e7\u0001\u00e8\u0001"+ + "\u00e8\u0001\u00e8\u0001\u00e8\u0001\u00e9\u0001\u00e9\u0001\u00e9\u0001"+ + "\u00e9\u0001\u00ea\u0001\u00ea\u0001\u00ea\u0001\u00ea\u0001\u00eb\u0001"+ + "\u00eb\u0001\u00eb\u0001\u00eb\u0001\u00eb\u0001\u00ec\u0001\u00ec\u0001"+ + "\u00ec\u0001\u00ec\u0001\u00ec\u0001\u00ed\u0001\u00ed\u0001\u00ed\u0001"+ + "\u00ed\u0001\u00ee\u0001\u00ee\u0001\u00ee\u0001\u00ee\u0001\u00ef\u0001"+ + "\u00ef\u0001\u00ef\u0001\u00ef\u0002\u02ff\u0344\u0000\u00f0\u0013\u0001"+ + "\u0015\u0002\u0017\u0003\u0019\u0004\u001b\u0005\u001d\u0006\u001f\u0007"+ + "!\b#\t%\n\'\u000b)\f+\r-\u000e/\u000f1\u00103\u00115\u00127\u00139\u0014"+ + ";\u0015=\u0016?\u0017A\u0018C\u0019E\u001aG\u001bI\u001cK\u001dM\u001e"+ + "O\u001fQ\u0000S\u0000U\u0000W\u0000Y\u0000[\u0000]\u0000_\u0000a\u0000"+ + "c\u0000e g!i\"k#m$o%q&s\'u(w)y*{+},\u007f-\u0081.\u0083/\u00850\u0087"+ + "1\u00892\u008b3\u008d4\u008f5\u00916\u00937\u00958\u00979\u0099:\u009b"+ + ";\u009d<\u009f=\u00a1>\u00a3?\u00a5@\u00a7A\u00a9B\u00abC\u00adD\u00af"+ + "E\u00b1F\u00b3\u0000\u00b5G\u00b7H\u00b9I\u00bbJ\u00bdK\u00bfL\u00c1\u0000"+ + "\u00c3M\u00c5N\u00c7O\u00c9P\u00cb\u0000\u00cd\u0000\u00cfQ\u00d1R\u00d3"+ + "S\u00d5\u0000\u00d7\u0000\u00d9\u0000\u00db\u0000\u00dd\u0000\u00df\u0000"+ + "\u00e1T\u00e3\u0000\u00e5U\u00e7\u0000\u00e9\u0000\u00ebV\u00edW\u00ef"+ + "X\u00f1\u0000\u00f3\u0000\u00f5\u0000\u00f7\u0000\u00f9\u0000\u00fb\u0000"+ + "\u00fd\u0000\u00ffY\u0101Z\u0103[\u0105\\\u0107\u0000\u0109\u0000\u010b"+ + "\u0000\u010d\u0000\u010f\u0000\u0111\u0000\u0113]\u0115\u0000\u0117^\u0119"+ + "_\u011b`\u011d\u0000\u011f\u0000\u0121a\u0123b\u0125\u0000\u0127c\u0129"+ + "\u0000\u012bd\u012de\u012ff\u0131\u0000\u0133\u0000\u0135\u0000\u0137"+ + "\u0000\u0139\u0000\u013b\u0000\u013d\u0000\u013f\u0000\u0141\u0000\u0143"+ + "g\u0145h\u0147i\u0149\u0000\u014b\u0000\u014d\u0000\u014f\u0000\u0151"+ + "\u0000\u0153\u0000\u0155j\u0157k\u0159l\u015b\u0000\u015dm\u015fn\u0161"+ + "o\u0163p\u0165\u0000\u0167\u0000\u0169q\u016br\u016ds\u016ft\u0171\u0000"+ + "\u0173\u0000\u0175\u0000\u0177\u0000\u0179\u0000\u017b\u0000\u017d\u0000"+ + "\u017fu\u0181v\u0183w\u0185\u0000\u0187\u0000\u0189\u0000\u018b\u0000"+ + "\u018dx\u018fy\u0191z\u0193\u0000\u0195{\u0197\u0000\u0199\u0000\u019b"+ + "|\u019d\u0000\u019f\u0000\u01a1\u0000\u01a3\u0000\u01a5\u0000\u01a7}\u01a9"+ + "~\u01ab\u007f\u01ad\u0000\u01af\u0000\u01b1\u0000\u01b3\u0080\u01b5\u0081"+ + "\u01b7\u0082\u01b9\u0000\u01bb\u0000\u01bd\u0083\u01bf\u0084\u01c1\u0085"+ + "\u01c3\u0000\u01c5\u0000\u01c7\u0000\u01c9\u0000\u01cb\u0000\u01cd\u0000"+ + "\u01cf\u0000\u01d1\u0000\u01d3\u0000\u01d5\u0000\u01d7\u0000\u01d9\u0086"+ + "\u01db\u0087\u01dd\u0088\u01df\u0000\u01e1\u0000\u01e3\u0089\u01e5\u008a"+ + "\u01e7\u008b\u01e9\u0000\u01eb\u0000\u01ed\u008c\u01ef\u008d\u01f1\u008e"+ + "\u0013\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r"+ + "\u000e\u000f\u0010\u0011\u0012$\u0002\u0000DDdd\u0002\u0000IIii\u0002"+ + "\u0000SSss\u0002\u0000EEee\u0002\u0000CCcc\u0002\u0000TTtt\u0002\u0000"+ + "RRrr\u0002\u0000OOoo\u0002\u0000PPpp\u0002\u0000NNnn\u0002\u0000HHhh\u0002"+ + "\u0000VVvv\u0002\u0000AAaa\u0002\u0000LLll\u0002\u0000XXxx\u0002\u0000"+ + "FFff\u0002\u0000MMmm\u0002\u0000GGgg\u0002\u0000KKkk\u0002\u0000WWww\u0002"+ + "\u0000UUuu\u0006\u0000\t\n\r\r //[[]]\u0002\u0000\n\n\r\r\u0003\u0000"+ + "\t\n\r\r \u0001\u000009\u0002\u0000AZaz\b\u0000\"\"NNRRTT\\\\nnrrtt\u0004"+ + "\u0000\n\n\r\r\"\"\\\\\u0002\u0000++--\u0001\u0000``\u0002\u0000BBbb\u0002"+ + "\u0000YYyy\u000b\u0000\t\n\r\r \"\",,//::==[[]]||\u0002\u0000**//\u000b"+ + "\u0000\t\n\r\r \"#,,//::<<>?\\\\||\u0002\u0000JJjj\u0710\u0000\u0013"+ + "\u0001\u0000\u0000\u0000\u0000\u0015\u0001\u0000\u0000\u0000\u0000\u0017"+ + "\u0001\u0000\u0000\u0000\u0000\u0019\u0001\u0000\u0000\u0000\u0000\u001b"+ + "\u0001\u0000\u0000\u0000\u0000\u001d\u0001\u0000\u0000\u0000\u0000\u001f"+ + "\u0001\u0000\u0000\u0000\u0000!\u0001\u0000\u0000\u0000\u0000#\u0001\u0000"+ + "\u0000\u0000\u0000%\u0001\u0000\u0000\u0000\u0000\'\u0001\u0000\u0000"+ + "\u0000\u0000)\u0001\u0000\u0000\u0000\u0000+\u0001\u0000\u0000\u0000\u0000"+ + "-\u0001\u0000\u0000\u0000\u0000/\u0001\u0000\u0000\u0000\u00001\u0001"+ + "\u0000\u0000\u0000\u00003\u0001\u0000\u0000\u0000\u00005\u0001\u0000\u0000"+ + "\u0000\u00007\u0001\u0000\u0000\u0000\u00009\u0001\u0000\u0000\u0000\u0000"+ + ";\u0001\u0000\u0000\u0000\u0000=\u0001\u0000\u0000\u0000\u0000?\u0001"+ + "\u0000\u0000\u0000\u0000A\u0001\u0000\u0000\u0000\u0000C\u0001\u0000\u0000"+ + "\u0000\u0000E\u0001\u0000\u0000\u0000\u0000G\u0001\u0000\u0000\u0000\u0000"+ + "I\u0001\u0000\u0000\u0000\u0000K\u0001\u0000\u0000\u0000\u0000M\u0001"+ + "\u0000\u0000\u0000\u0001O\u0001\u0000\u0000\u0000\u0001e\u0001\u0000\u0000"+ + "\u0000\u0001g\u0001\u0000\u0000\u0000\u0001i\u0001\u0000\u0000\u0000\u0001"+ + "k\u0001\u0000\u0000\u0000\u0001m\u0001\u0000\u0000\u0000\u0001o\u0001"+ + "\u0000\u0000\u0000\u0001q\u0001\u0000\u0000\u0000\u0001s\u0001\u0000\u0000"+ + "\u0000\u0001u\u0001\u0000\u0000\u0000\u0001w\u0001\u0000\u0000\u0000\u0001"+ + "y\u0001\u0000\u0000\u0000\u0001{\u0001\u0000\u0000\u0000\u0001}\u0001"+ + "\u0000\u0000\u0000\u0001\u007f\u0001\u0000\u0000\u0000\u0001\u0081\u0001"+ + "\u0000\u0000\u0000\u0001\u0083\u0001\u0000\u0000\u0000\u0001\u0085\u0001"+ + "\u0000\u0000\u0000\u0001\u0087\u0001\u0000\u0000\u0000\u0001\u0089\u0001"+ + "\u0000\u0000\u0000\u0001\u008b\u0001\u0000\u0000\u0000\u0001\u008d\u0001"+ + "\u0000\u0000\u0000\u0001\u008f\u0001\u0000\u0000\u0000\u0001\u0091\u0001"+ + "\u0000\u0000\u0000\u0001\u0093\u0001\u0000\u0000\u0000\u0001\u0095\u0001"+ + "\u0000\u0000\u0000\u0001\u0097\u0001\u0000\u0000\u0000\u0001\u0099\u0001"+ + "\u0000\u0000\u0000\u0001\u009b\u0001\u0000\u0000\u0000\u0001\u009d\u0001"+ + "\u0000\u0000\u0000\u0001\u009f\u0001\u0000\u0000\u0000\u0001\u00a1\u0001"+ + "\u0000\u0000\u0000\u0001\u00a3\u0001\u0000\u0000\u0000\u0001\u00a5\u0001"+ + "\u0000\u0000\u0000\u0001\u00a7\u0001\u0000\u0000\u0000\u0001\u00a9\u0001"+ + "\u0000\u0000\u0000\u0001\u00ab\u0001\u0000\u0000\u0000\u0001\u00ad\u0001"+ + "\u0000\u0000\u0000\u0001\u00af\u0001\u0000\u0000\u0000\u0001\u00b1\u0001"+ + "\u0000\u0000\u0000\u0001\u00b3\u0001\u0000\u0000\u0000\u0001\u00b5\u0001"+ + "\u0000\u0000\u0000\u0001\u00b7\u0001\u0000\u0000\u0000\u0001\u00b9\u0001"+ + "\u0000\u0000\u0000\u0001\u00bb\u0001\u0000\u0000\u0000\u0001\u00bd\u0001"+ + "\u0000\u0000\u0000\u0001\u00bf\u0001\u0000\u0000\u0000\u0001\u00c3\u0001"+ + "\u0000\u0000\u0000\u0001\u00c5\u0001\u0000\u0000\u0000\u0001\u00c7\u0001"+ + "\u0000\u0000\u0000\u0001\u00c9\u0001\u0000\u0000\u0000\u0002\u00cb\u0001"+ + "\u0000\u0000\u0000\u0002\u00cd\u0001\u0000\u0000\u0000\u0002\u00cf\u0001"+ + "\u0000\u0000\u0000\u0002\u00d1\u0001\u0000\u0000\u0000\u0002\u00d3\u0001"+ + "\u0000\u0000\u0000\u0003\u00d5\u0001\u0000\u0000\u0000\u0003\u00d7\u0001"+ + "\u0000\u0000\u0000\u0003\u00d9\u0001\u0000\u0000\u0000\u0003\u00db\u0001"+ + "\u0000\u0000\u0000\u0003\u00dd\u0001\u0000\u0000\u0000\u0003\u00df\u0001"+ + "\u0000\u0000\u0000\u0003\u00e1\u0001\u0000\u0000\u0000\u0003\u00e5\u0001"+ + "\u0000\u0000\u0000\u0003\u00e7\u0001\u0000\u0000\u0000\u0003\u00e9\u0001"+ + "\u0000\u0000\u0000\u0003\u00eb\u0001\u0000\u0000\u0000\u0003\u00ed\u0001"+ + "\u0000\u0000\u0000\u0003\u00ef\u0001\u0000\u0000\u0000\u0004\u00f1\u0001"+ + "\u0000\u0000\u0000\u0004\u00f3\u0001\u0000\u0000\u0000\u0004\u00f5\u0001"+ + "\u0000\u0000\u0000\u0004\u00f7\u0001\u0000\u0000\u0000\u0004\u00f9\u0001"+ + "\u0000\u0000\u0000\u0004\u00ff\u0001\u0000\u0000\u0000\u0004\u0101\u0001"+ + "\u0000\u0000\u0000\u0004\u0103\u0001\u0000\u0000\u0000\u0004\u0105\u0001"+ + "\u0000\u0000\u0000\u0005\u0107\u0001\u0000\u0000\u0000\u0005\u0109\u0001"+ + "\u0000\u0000\u0000\u0005\u010b\u0001\u0000\u0000\u0000\u0005\u010d\u0001"+ + "\u0000\u0000\u0000\u0005\u010f\u0001\u0000\u0000\u0000\u0005\u0111\u0001"+ + "\u0000\u0000\u0000\u0005\u0113\u0001\u0000\u0000\u0000\u0005\u0115\u0001"+ + "\u0000\u0000\u0000\u0005\u0117\u0001\u0000\u0000\u0000\u0005\u0119\u0001"+ + "\u0000\u0000\u0000\u0005\u011b\u0001\u0000\u0000\u0000\u0006\u011d\u0001"+ + "\u0000\u0000\u0000\u0006\u011f\u0001\u0000\u0000\u0000\u0006\u0121\u0001"+ + "\u0000\u0000\u0000\u0006\u0123\u0001\u0000\u0000\u0000\u0006\u0127\u0001"+ + "\u0000\u0000\u0000\u0006\u0129\u0001\u0000\u0000\u0000\u0006\u012b\u0001"+ + "\u0000\u0000\u0000\u0006\u012d\u0001\u0000\u0000\u0000\u0006\u012f\u0001"+ + "\u0000\u0000\u0000\u0007\u0131\u0001\u0000\u0000\u0000\u0007\u0133\u0001"+ + "\u0000\u0000\u0000\u0007\u0135\u0001\u0000\u0000\u0000\u0007\u0137\u0001"+ + "\u0000\u0000\u0000\u0007\u0139\u0001\u0000\u0000\u0000\u0007\u013b\u0001"+ + "\u0000\u0000\u0000\u0007\u013d\u0001\u0000\u0000\u0000\u0007\u013f\u0001"+ + "\u0000\u0000\u0000\u0007\u0141\u0001\u0000\u0000\u0000\u0007\u0143\u0001"+ + "\u0000\u0000\u0000\u0007\u0145\u0001\u0000\u0000\u0000\u0007\u0147\u0001"+ + "\u0000\u0000\u0000\b\u0149\u0001\u0000\u0000\u0000\b\u014b\u0001\u0000"+ "\u0000\u0000\b\u014d\u0001\u0000\u0000\u0000\b\u014f\u0001\u0000\u0000"+ "\u0000\b\u0151\u0001\u0000\u0000\u0000\b\u0153\u0001\u0000\u0000\u0000"+ "\b\u0155\u0001\u0000\u0000\u0000\b\u0157\u0001\u0000\u0000\u0000\b\u0159"+ - "\u0001\u0000\u0000\u0000\b\u015b\u0001\u0000\u0000\u0000\b\u015d\u0001"+ + "\u0001\u0000\u0000\u0000\t\u015b\u0001\u0000\u0000\u0000\t\u015d\u0001"+ "\u0000\u0000\u0000\t\u015f\u0001\u0000\u0000\u0000\t\u0161\u0001\u0000"+ - "\u0000\u0000\t\u0163\u0001\u0000\u0000\u0000\t\u0165\u0001\u0000\u0000"+ - "\u0000\t\u0167\u0001\u0000\u0000\u0000\n\u0169\u0001\u0000\u0000\u0000"+ + "\u0000\u0000\t\u0163\u0001\u0000\u0000\u0000\n\u0165\u0001\u0000\u0000"+ + "\u0000\n\u0167\u0001\u0000\u0000\u0000\n\u0169\u0001\u0000\u0000\u0000"+ "\n\u016b\u0001\u0000\u0000\u0000\n\u016d\u0001\u0000\u0000\u0000\n\u016f"+ - "\u0001\u0000\u0000\u0000\n\u0171\u0001\u0000\u0000\u0000\n\u0173\u0001"+ - "\u0000\u0000\u0000\u000b\u0175\u0001\u0000\u0000\u0000\u000b\u0177\u0001"+ - "\u0000\u0000\u0000\u000b\u0179\u0001\u0000\u0000\u0000\u000b\u017b\u0001"+ - "\u0000\u0000\u0000\u000b\u017d\u0001\u0000\u0000\u0000\u000b\u017f\u0001"+ - "\u0000\u0000\u0000\u000b\u0181\u0001\u0000\u0000\u0000\u000b\u0183\u0001"+ - "\u0000\u0000\u0000\u000b\u0185\u0001\u0000\u0000\u0000\u000b\u0187\u0001"+ + "\u0001\u0000\u0000\u0000\u000b\u0171\u0001\u0000\u0000\u0000\u000b\u0173"+ + "\u0001\u0000\u0000\u0000\u000b\u0175\u0001\u0000\u0000\u0000\u000b\u0177"+ + "\u0001\u0000\u0000\u0000\u000b\u0179\u0001\u0000\u0000\u0000\u000b\u017b"+ + "\u0001\u0000\u0000\u0000\u000b\u017d\u0001\u0000\u0000\u0000\u000b\u017f"+ + "\u0001\u0000\u0000\u0000\u000b\u0181\u0001\u0000\u0000\u0000\u000b\u0183"+ + "\u0001\u0000\u0000\u0000\f\u0185\u0001\u0000\u0000\u0000\f\u0187\u0001"+ "\u0000\u0000\u0000\f\u0189\u0001\u0000\u0000\u0000\f\u018b\u0001\u0000"+ "\u0000\u0000\f\u018d\u0001\u0000\u0000\u0000\f\u018f\u0001\u0000\u0000"+ - "\u0000\f\u0191\u0001\u0000\u0000\u0000\f\u0193\u0001\u0000\u0000\u0000"+ - "\f\u0195\u0001\u0000\u0000\u0000\r\u0197\u0001\u0000\u0000\u0000\r\u0199"+ + "\u0000\f\u0191\u0001\u0000\u0000\u0000\r\u0193\u0001\u0000\u0000\u0000"+ + "\r\u0195\u0001\u0000\u0000\u0000\r\u0197\u0001\u0000\u0000\u0000\r\u0199"+ "\u0001\u0000\u0000\u0000\r\u019b\u0001\u0000\u0000\u0000\r\u019d\u0001"+ "\u0000\u0000\u0000\r\u019f\u0001\u0000\u0000\u0000\r\u01a1\u0001\u0000"+ "\u0000\u0000\r\u01a3\u0001\u0000\u0000\u0000\r\u01a5\u0001\u0000\u0000"+ "\u0000\r\u01a7\u0001\u0000\u0000\u0000\r\u01a9\u0001\u0000\u0000\u0000"+ - "\r\u01ab\u0001\u0000\u0000\u0000\r\u01ad\u0001\u0000\u0000\u0000\r\u01af"+ - "\u0001\u0000\u0000\u0000\u000e\u01b1\u0001\u0000\u0000\u0000\u000e\u01b3"+ - "\u0001\u0000\u0000\u0000\u000e\u01b5\u0001\u0000\u0000\u0000\u000e\u01b7"+ - "\u0001\u0000\u0000\u0000\u000e\u01b9\u0001\u0000\u0000\u0000\u000e\u01bb"+ - "\u0001\u0000\u0000\u0000\u000f\u01bd\u0001\u0000\u0000\u0000\u000f\u01bf"+ - "\u0001\u0000\u0000\u0000\u000f\u01c1\u0001\u0000\u0000\u0000\u000f\u01c3"+ - "\u0001\u0000\u0000\u0000\u000f\u01c5\u0001\u0000\u0000\u0000\u000f\u01c7"+ - "\u0001\u0000\u0000\u0000\u000f\u01c9\u0001\u0000\u0000\u0000\u000f\u01cb"+ - "\u0001\u0000\u0000\u0000\u000f\u01cd\u0001\u0000\u0000\u0000\u0010\u01cf"+ - "\u0001\u0000\u0000\u0000\u0010\u01d1\u0001\u0000\u0000\u0000\u0010\u01d3"+ - "\u0001\u0000\u0000\u0000\u0010\u01d5\u0001\u0000\u0000\u0000\u0010\u01d7"+ - "\u0001\u0000\u0000\u0000\u0010\u01d9\u0001\u0000\u0000\u0000\u0010\u01db"+ - "\u0001\u0000\u0000\u0000\u0010\u01dd\u0001\u0000\u0000\u0000\u0010\u01df"+ - "\u0001\u0000\u0000\u0000\u0010\u01e1\u0001\u0000\u0000\u0000\u0011\u01e3"+ - "\u0001\u0000\u0000\u0000\u0011\u01e5\u0001\u0000\u0000\u0000\u0011\u01e7"+ - "\u0001\u0000\u0000\u0000\u0011\u01e9\u0001\u0000\u0000\u0000\u0011\u01eb"+ - "\u0001\u0000\u0000\u0000\u0012\u01ed\u0001\u0000\u0000\u0000\u0012\u01ef"+ - "\u0001\u0000\u0000\u0000\u0012\u01f1\u0001\u0000\u0000\u0000\u0012\u01f3"+ - "\u0001\u0000\u0000\u0000\u0012\u01f5\u0001\u0000\u0000\u0000\u0012\u01f7"+ - "\u0001\u0000\u0000\u0000\u0013\u01f9\u0001\u0000\u0000\u0000\u0015\u0203"+ - "\u0001\u0000\u0000\u0000\u0017\u020a\u0001\u0000\u0000\u0000\u0019\u0213"+ - "\u0001\u0000\u0000\u0000\u001b\u021a\u0001\u0000\u0000\u0000\u001d\u0224"+ - "\u0001\u0000\u0000\u0000\u001f\u022b\u0001\u0000\u0000\u0000!\u0232\u0001"+ - "\u0000\u0000\u0000#\u0239\u0001\u0000\u0000\u0000%\u0241\u0001\u0000\u0000"+ - "\u0000\'\u024d\u0001\u0000\u0000\u0000)\u0256\u0001\u0000\u0000\u0000"+ - "+\u025c\u0001\u0000\u0000\u0000-\u0263\u0001\u0000\u0000\u0000/\u026a"+ - "\u0001\u0000\u0000\u00001\u0272\u0001\u0000\u0000\u00003\u027a\u0001\u0000"+ - "\u0000\u00005\u0283\u0001\u0000\u0000\u00007\u0293\u0001\u0000\u0000\u0000"+ - "9\u02a2\u0001\u0000\u0000\u0000;\u02ae\u0001\u0000\u0000\u0000=\u02ba"+ - "\u0001\u0000\u0000\u0000?\u02c5\u0001\u0000\u0000\u0000A\u02cd\u0001\u0000"+ - "\u0000\u0000C\u02d5\u0001\u0000\u0000\u0000E\u02de\u0001\u0000\u0000\u0000"+ - "G\u02e7\u0001\u0000\u0000\u0000I\u02ed\u0001\u0000\u0000\u0000K\u02fe"+ - "\u0001\u0000\u0000\u0000M\u030e\u0001\u0000\u0000\u0000O\u0314\u0001\u0000"+ - "\u0000\u0000Q\u0318\u0001\u0000\u0000\u0000S\u031a\u0001\u0000\u0000\u0000"+ - "U\u031c\u0001\u0000\u0000\u0000W\u031f\u0001\u0000\u0000\u0000Y\u0321"+ - "\u0001\u0000\u0000\u0000[\u032a\u0001\u0000\u0000\u0000]\u032c\u0001\u0000"+ - "\u0000\u0000_\u0331\u0001\u0000\u0000\u0000a\u0333\u0001\u0000\u0000\u0000"+ - "c\u0338\u0001\u0000\u0000\u0000e\u0357\u0001\u0000\u0000\u0000g\u035a"+ - "\u0001\u0000\u0000\u0000i\u0388\u0001\u0000\u0000\u0000k\u038a\u0001\u0000"+ - "\u0000\u0000m\u038d\u0001\u0000\u0000\u0000o\u0391\u0001\u0000\u0000\u0000"+ - "q\u0395\u0001\u0000\u0000\u0000s\u0397\u0001\u0000\u0000\u0000u\u039a"+ - "\u0001\u0000\u0000\u0000w\u039c\u0001\u0000\u0000\u0000y\u039e\u0001\u0000"+ - "\u0000\u0000{\u03a3\u0001\u0000\u0000\u0000}\u03a5\u0001\u0000\u0000\u0000"+ - "\u007f\u03ab\u0001\u0000\u0000\u0000\u0081\u03b1\u0001\u0000\u0000\u0000"+ - "\u0083\u03b4\u0001\u0000\u0000\u0000\u0085\u03b7\u0001\u0000\u0000\u0000"+ - "\u0087\u03bc\u0001\u0000\u0000\u0000\u0089\u03c1\u0001\u0000\u0000\u0000"+ - "\u008b\u03c3\u0001\u0000\u0000\u0000\u008d\u03c7\u0001\u0000\u0000\u0000"+ - "\u008f\u03cc\u0001\u0000\u0000\u0000\u0091\u03d2\u0001\u0000\u0000\u0000"+ - "\u0093\u03d5\u0001\u0000\u0000\u0000\u0095\u03d7\u0001\u0000\u0000\u0000"+ - "\u0097\u03dd\u0001\u0000\u0000\u0000\u0099\u03df\u0001\u0000\u0000\u0000"+ - "\u009b\u03e4\u0001\u0000\u0000\u0000\u009d\u03e7\u0001\u0000\u0000\u0000"+ - "\u009f\u03ea\u0001\u0000\u0000\u0000\u00a1\u03ed\u0001\u0000\u0000\u0000"+ - "\u00a3\u03ef\u0001\u0000\u0000\u0000\u00a5\u03f2\u0001\u0000\u0000\u0000"+ - "\u00a7\u03f4\u0001\u0000\u0000\u0000\u00a9\u03f7\u0001\u0000\u0000\u0000"+ - "\u00ab\u03f9\u0001\u0000\u0000\u0000\u00ad\u03fb\u0001\u0000\u0000\u0000"+ - "\u00af\u03fd\u0001\u0000\u0000\u0000\u00b1\u03ff\u0001\u0000\u0000\u0000"+ - "\u00b3\u0401\u0001\u0000\u0000\u0000\u00b5\u0403\u0001\u0000\u0000\u0000"+ - "\u00b7\u0405\u0001\u0000\u0000\u0000\u00b9\u0409\u0001\u0000\u0000\u0000"+ - "\u00bb\u040e\u0001\u0000\u0000\u0000\u00bd\u0424\u0001\u0000\u0000\u0000"+ - "\u00bf\u0426\u0001\u0000\u0000\u0000\u00c1\u042b\u0001\u0000\u0000\u0000"+ - "\u00c3\u0440\u0001\u0000\u0000\u0000\u00c5\u0442\u0001\u0000\u0000\u0000"+ - "\u00c7\u044a\u0001\u0000\u0000\u0000\u00c9\u044c\u0001\u0000\u0000\u0000"+ - "\u00cb\u0450\u0001\u0000\u0000\u0000\u00cd\u0454\u0001\u0000\u0000\u0000"+ - "\u00cf\u0458\u0001\u0000\u0000\u0000\u00d1\u045d\u0001\u0000\u0000\u0000"+ - "\u00d3\u0462\u0001\u0000\u0000\u0000\u00d5\u0466\u0001\u0000\u0000\u0000"+ - "\u00d7\u046a\u0001\u0000\u0000\u0000\u00d9\u046e\u0001\u0000\u0000\u0000"+ - "\u00db\u0473\u0001\u0000\u0000\u0000\u00dd\u0477\u0001\u0000\u0000\u0000"+ - "\u00df\u047b\u0001\u0000\u0000\u0000\u00e1\u047f\u0001\u0000\u0000\u0000"+ - "\u00e3\u0483\u0001\u0000\u0000\u0000\u00e5\u0487\u0001\u0000\u0000\u0000"+ - "\u00e7\u0493\u0001\u0000\u0000\u0000\u00e9\u0496\u0001\u0000\u0000\u0000"+ - "\u00eb\u049a\u0001\u0000\u0000\u0000\u00ed\u049e\u0001\u0000\u0000\u0000"+ - "\u00ef\u04a2\u0001\u0000\u0000\u0000\u00f1\u04a6\u0001\u0000\u0000\u0000"+ - "\u00f3\u04aa\u0001\u0000\u0000\u0000\u00f5\u04ae\u0001\u0000\u0000\u0000"+ - "\u00f7\u04b3\u0001\u0000\u0000\u0000\u00f9\u04b7\u0001\u0000\u0000\u0000"+ - "\u00fb\u04bb\u0001\u0000\u0000\u0000\u00fd\u04bf\u0001\u0000\u0000\u0000"+ - "\u00ff\u04c7\u0001\u0000\u0000\u0000\u0101\u04dc\u0001\u0000\u0000\u0000"+ - "\u0103\u04e0\u0001\u0000\u0000\u0000\u0105\u04e4\u0001\u0000\u0000\u0000"+ - "\u0107\u04e8\u0001\u0000\u0000\u0000\u0109\u04ec\u0001\u0000\u0000\u0000"+ - "\u010b\u04f0\u0001\u0000\u0000\u0000\u010d\u04f5\u0001\u0000\u0000\u0000"+ - "\u010f\u04f9\u0001\u0000\u0000\u0000\u0111\u04fd\u0001\u0000\u0000\u0000"+ - "\u0113\u0501\u0001\u0000\u0000\u0000\u0115\u0505\u0001\u0000\u0000\u0000"+ - "\u0117\u0509\u0001\u0000\u0000\u0000\u0119\u050c\u0001\u0000\u0000\u0000"+ - "\u011b\u0510\u0001\u0000\u0000\u0000\u011d\u0514\u0001\u0000\u0000\u0000"+ - "\u011f\u0518\u0001\u0000\u0000\u0000\u0121\u051c\u0001\u0000\u0000\u0000"+ - "\u0123\u0521\u0001\u0000\u0000\u0000\u0125\u0526\u0001\u0000\u0000\u0000"+ - "\u0127\u052b\u0001\u0000\u0000\u0000\u0129\u0532\u0001\u0000\u0000\u0000"+ - "\u012b\u053b\u0001\u0000\u0000\u0000\u012d\u0542\u0001\u0000\u0000\u0000"+ - "\u012f\u0546\u0001\u0000\u0000\u0000\u0131\u054a\u0001\u0000\u0000\u0000"+ - "\u0133\u054e\u0001\u0000\u0000\u0000\u0135\u0552\u0001\u0000\u0000\u0000"+ - "\u0137\u0558\u0001\u0000\u0000\u0000\u0139\u055c\u0001\u0000\u0000\u0000"+ - "\u013b\u0560\u0001\u0000\u0000\u0000\u013d\u0564\u0001\u0000\u0000\u0000"+ - "\u013f\u0568\u0001\u0000\u0000\u0000\u0141\u056c\u0001\u0000\u0000\u0000"+ - "\u0143\u0570\u0001\u0000\u0000\u0000\u0145\u0574\u0001\u0000\u0000\u0000"+ - "\u0147\u0578\u0001\u0000\u0000\u0000\u0149\u057c\u0001\u0000\u0000\u0000"+ - "\u014b\u0580\u0001\u0000\u0000\u0000\u014d\u0584\u0001\u0000\u0000\u0000"+ - "\u014f\u0589\u0001\u0000\u0000\u0000\u0151\u058d\u0001\u0000\u0000\u0000"+ - "\u0153\u0591\u0001\u0000\u0000\u0000\u0155\u0595\u0001\u0000\u0000\u0000"+ - "\u0157\u0599\u0001\u0000\u0000\u0000\u0159\u059d\u0001\u0000\u0000\u0000"+ - "\u015b\u05a1\u0001\u0000\u0000\u0000\u015d\u05a5\u0001\u0000\u0000\u0000"+ - "\u015f\u05a9\u0001\u0000\u0000\u0000\u0161\u05ae\u0001\u0000\u0000\u0000"+ - "\u0163\u05b3\u0001\u0000\u0000\u0000\u0165\u05b7\u0001\u0000\u0000\u0000"+ - "\u0167\u05bb\u0001\u0000\u0000\u0000\u0169\u05bf\u0001\u0000\u0000\u0000"+ - "\u016b\u05c4\u0001\u0000\u0000\u0000\u016d\u05cd\u0001\u0000\u0000\u0000"+ - "\u016f\u05d1\u0001\u0000\u0000\u0000\u0171\u05d5\u0001\u0000\u0000\u0000"+ - "\u0173\u05d9\u0001\u0000\u0000\u0000\u0175\u05dd\u0001\u0000\u0000\u0000"+ - "\u0177\u05e2\u0001\u0000\u0000\u0000\u0179\u05e6\u0001\u0000\u0000\u0000"+ - "\u017b\u05ea\u0001\u0000\u0000\u0000\u017d\u05ee\u0001\u0000\u0000\u0000"+ - "\u017f\u05f3\u0001\u0000\u0000\u0000\u0181\u05f7\u0001\u0000\u0000\u0000"+ - "\u0183\u05fb\u0001\u0000\u0000\u0000\u0185\u05ff\u0001\u0000\u0000\u0000"+ - "\u0187\u0603\u0001\u0000\u0000\u0000\u0189\u0607\u0001\u0000\u0000\u0000"+ - "\u018b\u060d\u0001\u0000\u0000\u0000\u018d\u0611\u0001\u0000\u0000\u0000"+ - "\u018f\u0615\u0001\u0000\u0000\u0000\u0191\u0619\u0001\u0000\u0000\u0000"+ - "\u0193\u061d\u0001\u0000\u0000\u0000\u0195\u0621\u0001\u0000\u0000\u0000"+ - "\u0197\u0625\u0001\u0000\u0000\u0000\u0199\u062a\u0001\u0000\u0000\u0000"+ - "\u019b\u062f\u0001\u0000\u0000\u0000\u019d\u0633\u0001\u0000\u0000\u0000"+ - "\u019f\u0639\u0001\u0000\u0000\u0000\u01a1\u0642\u0001\u0000\u0000\u0000"+ - "\u01a3\u0646\u0001\u0000\u0000\u0000\u01a5\u064a\u0001\u0000\u0000\u0000"+ - "\u01a7\u064e\u0001\u0000\u0000\u0000\u01a9\u0652\u0001\u0000\u0000\u0000"+ - "\u01ab\u0656\u0001\u0000\u0000\u0000\u01ad\u065a\u0001\u0000\u0000\u0000"+ - "\u01af\u065e\u0001\u0000\u0000\u0000\u01b1\u0662\u0001\u0000\u0000\u0000"+ - "\u01b3\u0667\u0001\u0000\u0000\u0000\u01b5\u066d\u0001\u0000\u0000\u0000"+ - "\u01b7\u0673\u0001\u0000\u0000\u0000\u01b9\u0677\u0001\u0000\u0000\u0000"+ - "\u01bb\u067b\u0001\u0000\u0000\u0000\u01bd\u067f\u0001\u0000\u0000\u0000"+ - "\u01bf\u0685\u0001\u0000\u0000\u0000\u01c1\u068b\u0001\u0000\u0000\u0000"+ - "\u01c3\u068f\u0001\u0000\u0000\u0000\u01c5\u0693\u0001\u0000\u0000\u0000"+ - "\u01c7\u0697\u0001\u0000\u0000\u0000\u01c9\u069d\u0001\u0000\u0000\u0000"+ - "\u01cb\u06a3\u0001\u0000\u0000\u0000\u01cd\u06a9\u0001\u0000\u0000\u0000"+ - "\u01cf\u06ae\u0001\u0000\u0000\u0000\u01d1\u06b3\u0001\u0000\u0000\u0000"+ - "\u01d3\u06b7\u0001\u0000\u0000\u0000\u01d5\u06bb\u0001\u0000\u0000\u0000"+ - "\u01d7\u06bf\u0001\u0000\u0000\u0000\u01d9\u06c3\u0001\u0000\u0000\u0000"+ - "\u01db\u06c7\u0001\u0000\u0000\u0000\u01dd\u06cb\u0001\u0000\u0000\u0000"+ - "\u01df\u06cf\u0001\u0000\u0000\u0000\u01e1\u06d3\u0001\u0000\u0000\u0000"+ - "\u01e3\u06d7\u0001\u0000\u0000\u0000\u01e5\u06dc\u0001\u0000\u0000\u0000"+ - "\u01e7\u06e0\u0001\u0000\u0000\u0000\u01e9\u06e4\u0001\u0000\u0000\u0000"+ - "\u01eb\u06e8\u0001\u0000\u0000\u0000\u01ed\u06ec\u0001\u0000\u0000\u0000"+ - "\u01ef\u06f1\u0001\u0000\u0000\u0000\u01f1\u06f6\u0001\u0000\u0000\u0000"+ - "\u01f3\u06fb\u0001\u0000\u0000\u0000\u01f5\u06ff\u0001\u0000\u0000\u0000"+ - "\u01f7\u0703\u0001\u0000\u0000\u0000\u01f9\u01fa\u0007\u0000\u0000\u0000"+ - "\u01fa\u01fb\u0007\u0001\u0000\u0000\u01fb\u01fc\u0007\u0002\u0000\u0000"+ - "\u01fc\u01fd\u0007\u0002\u0000\u0000\u01fd\u01fe\u0007\u0003\u0000\u0000"+ - "\u01fe\u01ff\u0007\u0004\u0000\u0000\u01ff\u0200\u0007\u0005\u0000\u0000"+ - "\u0200\u0201\u0001\u0000\u0000\u0000\u0201\u0202\u0006\u0000\u0000\u0000"+ - "\u0202\u0014\u0001\u0000\u0000\u0000\u0203\u0204\u0007\u0000\u0000\u0000"+ - "\u0204\u0205\u0007\u0006\u0000\u0000\u0205\u0206\u0007\u0007\u0000\u0000"+ - "\u0206\u0207\u0007\b\u0000\u0000\u0207\u0208\u0001\u0000\u0000\u0000\u0208"+ - "\u0209\u0006\u0001\u0001\u0000\u0209\u0016\u0001\u0000\u0000\u0000\u020a"+ - "\u020b\u0007\u0003\u0000\u0000\u020b\u020c\u0007\t\u0000\u0000\u020c\u020d"+ - "\u0007\u0006\u0000\u0000\u020d\u020e\u0007\u0001\u0000\u0000\u020e\u020f"+ - "\u0007\u0004\u0000\u0000\u020f\u0210\u0007\n\u0000\u0000\u0210\u0211\u0001"+ - "\u0000\u0000\u0000\u0211\u0212\u0006\u0002\u0002\u0000\u0212\u0018\u0001"+ - "\u0000\u0000\u0000\u0213\u0214\u0007\u0003\u0000\u0000\u0214\u0215\u0007"+ - "\u000b\u0000\u0000\u0215\u0216\u0007\f\u0000\u0000\u0216\u0217\u0007\r"+ - "\u0000\u0000\u0217\u0218\u0001\u0000\u0000\u0000\u0218\u0219\u0006\u0003"+ - "\u0000\u0000\u0219\u001a\u0001\u0000\u0000\u0000\u021a\u021b\u0007\u0003"+ - "\u0000\u0000\u021b\u021c\u0007\u000e\u0000\u0000\u021c\u021d\u0007\b\u0000"+ - "\u0000\u021d\u021e\u0007\r\u0000\u0000\u021e\u021f\u0007\f\u0000\u0000"+ - "\u021f\u0220\u0007\u0001\u0000\u0000\u0220\u0221\u0007\t\u0000\u0000\u0221"+ - "\u0222\u0001\u0000\u0000\u0000\u0222\u0223\u0006\u0004\u0003\u0000\u0223"+ - "\u001c\u0001\u0000\u0000\u0000\u0224\u0225\u0007\u000f\u0000\u0000\u0225"+ - "\u0226\u0007\u0006\u0000\u0000\u0226\u0227\u0007\u0007\u0000\u0000\u0227"+ - "\u0228\u0007\u0010\u0000\u0000\u0228\u0229\u0001\u0000\u0000\u0000\u0229"+ - "\u022a\u0006\u0005\u0004\u0000\u022a\u001e\u0001\u0000\u0000\u0000\u022b"+ - "\u022c\u0007\u0011\u0000\u0000\u022c\u022d\u0007\u0006\u0000\u0000\u022d"+ - "\u022e\u0007\u0007\u0000\u0000\u022e\u022f\u0007\u0012\u0000\u0000\u022f"+ - "\u0230\u0001\u0000\u0000\u0000\u0230\u0231\u0006\u0006\u0000\u0000\u0231"+ - " \u0001\u0000\u0000\u0000\u0232\u0233\u0007\u0012\u0000\u0000\u0233\u0234"+ - "\u0007\u0003\u0000\u0000\u0234\u0235\u0007\u0003\u0000\u0000\u0235\u0236"+ - "\u0007\b\u0000\u0000\u0236\u0237\u0001\u0000\u0000\u0000\u0237\u0238\u0006"+ - "\u0007\u0001\u0000\u0238\"\u0001\u0000\u0000\u0000\u0239\u023a\u0007\r"+ - "\u0000\u0000\u023a\u023b\u0007\u0001\u0000\u0000\u023b\u023c\u0007\u0010"+ - "\u0000\u0000\u023c\u023d\u0007\u0001\u0000\u0000\u023d\u023e\u0007\u0005"+ - "\u0000\u0000\u023e\u023f\u0001\u0000\u0000\u0000\u023f\u0240\u0006\b\u0000"+ - "\u0000\u0240$\u0001\u0000\u0000\u0000\u0241\u0242\u0007\u0010\u0000\u0000"+ - "\u0242\u0243\u0007\u000b\u0000\u0000\u0243\u0244\u0005_\u0000\u0000\u0244"+ - "\u0245\u0007\u0003\u0000\u0000\u0245\u0246\u0007\u000e\u0000\u0000\u0246"+ - "\u0247\u0007\b\u0000\u0000\u0247\u0248\u0007\f\u0000\u0000\u0248\u0249"+ - "\u0007\t\u0000\u0000\u0249\u024a\u0007\u0000\u0000\u0000\u024a\u024b\u0001"+ - "\u0000\u0000\u0000\u024b\u024c\u0006\t\u0005\u0000\u024c&\u0001\u0000"+ - "\u0000\u0000\u024d\u024e\u0007\u0006\u0000\u0000\u024e\u024f\u0007\u0003"+ - "\u0000\u0000\u024f\u0250\u0007\t\u0000\u0000\u0250\u0251\u0007\f\u0000"+ - "\u0000\u0251\u0252\u0007\u0010\u0000\u0000\u0252\u0253\u0007\u0003\u0000"+ - "\u0000\u0253\u0254\u0001\u0000\u0000\u0000\u0254\u0255\u0006\n\u0006\u0000"+ - "\u0255(\u0001\u0000\u0000\u0000\u0256\u0257\u0007\u0006\u0000\u0000\u0257"+ - "\u0258\u0007\u0007\u0000\u0000\u0258\u0259\u0007\u0013\u0000\u0000\u0259"+ - "\u025a\u0001\u0000\u0000\u0000\u025a\u025b\u0006\u000b\u0000\u0000\u025b"+ - "*\u0001\u0000\u0000\u0000\u025c\u025d\u0007\u0002\u0000\u0000\u025d\u025e"+ - "\u0007\n\u0000\u0000\u025e\u025f\u0007\u0007\u0000\u0000\u025f\u0260\u0007"+ - "\u0013\u0000\u0000\u0260\u0261\u0001\u0000\u0000\u0000\u0261\u0262\u0006"+ - "\f\u0007\u0000\u0262,\u0001\u0000\u0000\u0000\u0263\u0264\u0007\u0002"+ - "\u0000\u0000\u0264\u0265\u0007\u0007\u0000\u0000\u0265\u0266\u0007\u0006"+ - "\u0000\u0000\u0266\u0267\u0007\u0005\u0000\u0000\u0267\u0268\u0001\u0000"+ - "\u0000\u0000\u0268\u0269\u0006\r\u0000\u0000\u0269.\u0001\u0000\u0000"+ - "\u0000\u026a\u026b\u0007\u0002\u0000\u0000\u026b\u026c\u0007\u0005\u0000"+ - "\u0000\u026c\u026d\u0007\f\u0000\u0000\u026d\u026e\u0007\u0005\u0000\u0000"+ - "\u026e\u026f\u0007\u0002\u0000\u0000\u026f\u0270\u0001\u0000\u0000\u0000"+ - "\u0270\u0271\u0006\u000e\u0000\u0000\u02710\u0001\u0000\u0000\u0000\u0272"+ - "\u0273\u0007\u0013\u0000\u0000\u0273\u0274\u0007\n\u0000\u0000\u0274\u0275"+ - "\u0007\u0003\u0000\u0000\u0275\u0276\u0007\u0006\u0000\u0000\u0276\u0277"+ - "\u0007\u0003\u0000\u0000\u0277\u0278\u0001\u0000\u0000\u0000\u0278\u0279"+ - "\u0006\u000f\u0000\u0000\u02792\u0001\u0000\u0000\u0000\u027a\u027b\u0007"+ - "\r\u0000\u0000\u027b\u027c\u0007\u0007\u0000\u0000\u027c\u027d\u0007\u0007"+ - "\u0000\u0000\u027d\u027e\u0007\u0012\u0000\u0000\u027e\u027f\u0007\u0014"+ - "\u0000\u0000\u027f\u0280\u0007\b\u0000\u0000\u0280\u0281\u0001\u0000\u0000"+ - "\u0000\u0281\u0282\u0006\u0010\b\u0000\u02824\u0001\u0000\u0000\u0000"+ - "\u0283\u0284\u0004\u0011\u0000\u0000\u0284\u0285\u0007\u0004\u0000\u0000"+ - "\u0285\u0286\u0007\n\u0000\u0000\u0286\u0287\u0007\f\u0000\u0000\u0287"+ - "\u0288\u0007\t\u0000\u0000\u0288\u0289\u0007\u0011\u0000\u0000\u0289\u028a"+ - "\u0007\u0003\u0000\u0000\u028a\u028b\u0005_\u0000\u0000\u028b\u028c\u0007"+ - "\b\u0000\u0000\u028c\u028d\u0007\u0007\u0000\u0000\u028d\u028e\u0007\u0001"+ - "\u0000\u0000\u028e\u028f\u0007\t\u0000\u0000\u028f\u0290\u0007\u0005\u0000"+ - "\u0000\u0290\u0291\u0001\u0000\u0000\u0000\u0291\u0292\u0006\u0011\t\u0000"+ - "\u02926\u0001\u0000\u0000\u0000\u0293\u0294\u0004\u0012\u0001\u0000\u0294"+ - "\u0295\u0007\u0001\u0000\u0000\u0295\u0296\u0007\t\u0000\u0000\u0296\u0297"+ - "\u0007\r\u0000\u0000\u0297\u0298\u0007\u0001\u0000\u0000\u0298\u0299\u0007"+ - "\t\u0000\u0000\u0299\u029a\u0007\u0003\u0000\u0000\u029a\u029b\u0007\u0002"+ - "\u0000\u0000\u029b\u029c\u0007\u0005\u0000\u0000\u029c\u029d\u0007\f\u0000"+ - "\u0000\u029d\u029e\u0007\u0005\u0000\u0000\u029e\u029f\u0007\u0002\u0000"+ - "\u0000\u029f\u02a0\u0001\u0000\u0000\u0000\u02a0\u02a1\u0006\u0012\u0000"+ - "\u0000\u02a18\u0001\u0000\u0000\u0000\u02a2\u02a3\u0004\u0013\u0002\u0000"+ - "\u02a3\u02a4\u0007\u0001\u0000\u0000\u02a4\u02a5\u0007\t\u0000\u0000\u02a5"+ - "\u02a6\u0007\u0002\u0000\u0000\u02a6\u02a7\u0007\u0001\u0000\u0000\u02a7"+ - "\u02a8\u0007\u0002\u0000\u0000\u02a8\u02a9\u0007\u0005\u0000\u0000\u02a9"+ - "\u02aa\u0005_\u0000\u0000\u02aa\u02ab\u0005\u8001\uf414\u0000\u0000\u02ab"+ - "\u02ac\u0001\u0000\u0000\u0000\u02ac\u02ad\u0006\u0013\u0001\u0000\u02ad"+ - ":\u0001\u0000\u0000\u0000\u02ae\u02af\u0004\u0014\u0003\u0000\u02af\u02b0"+ - "\u0007\r\u0000\u0000\u02b0\u02b1\u0007\u0007\u0000\u0000\u02b1\u02b2\u0007"+ - "\u0007\u0000\u0000\u02b2\u02b3\u0007\u0012\u0000\u0000\u02b3\u02b4\u0007"+ - "\u0014\u0000\u0000\u02b4\u02b5\u0007\b\u0000\u0000\u02b5\u02b6\u0005_"+ - "\u0000\u0000\u02b6\u02b7\u0005\u8001\uf414\u0000\u0000\u02b7\u02b8\u0001"+ - "\u0000\u0000\u0000\u02b8\u02b9\u0006\u0014\n\u0000\u02b9<\u0001\u0000"+ - "\u0000\u0000\u02ba\u02bb\u0004\u0015\u0004\u0000\u02bb\u02bc\u0007\u0010"+ - "\u0000\u0000\u02bc\u02bd\u0007\u0003\u0000\u0000\u02bd\u02be\u0007\u0005"+ - "\u0000\u0000\u02be\u02bf\u0007\u0006\u0000\u0000\u02bf\u02c0\u0007\u0001"+ - "\u0000\u0000\u02c0\u02c1\u0007\u0004\u0000\u0000\u02c1\u02c2\u0007\u0002"+ - "\u0000\u0000\u02c2\u02c3\u0001\u0000\u0000\u0000\u02c3\u02c4\u0006\u0015"+ - "\u000b\u0000\u02c4>\u0001\u0000\u0000\u0000\u02c5\u02c6\u0004\u0016\u0005"+ - "\u0000\u02c6\u02c7\u0007\u000f\u0000\u0000\u02c7\u02c8\u0007\u0014\u0000"+ - "\u0000\u02c8\u02c9\u0007\r\u0000\u0000\u02c9\u02ca\u0007\r\u0000\u0000"+ - "\u02ca\u02cb\u0001\u0000\u0000\u0000\u02cb\u02cc\u0006\u0016\b\u0000\u02cc"+ - "@\u0001\u0000\u0000\u0000\u02cd\u02ce\u0004\u0017\u0006\u0000\u02ce\u02cf"+ - "\u0007\r\u0000\u0000\u02cf\u02d0\u0007\u0003\u0000\u0000\u02d0\u02d1\u0007"+ - "\u000f\u0000\u0000\u02d1\u02d2\u0007\u0005\u0000\u0000\u02d2\u02d3\u0001"+ - "\u0000\u0000\u0000\u02d3\u02d4\u0006\u0017\b\u0000\u02d4B\u0001\u0000"+ - "\u0000\u0000\u02d5\u02d6\u0004\u0018\u0007\u0000\u02d6\u02d7\u0007\u0006"+ - "\u0000\u0000\u02d7\u02d8\u0007\u0001\u0000\u0000\u02d8\u02d9\u0007\u0011"+ - "\u0000\u0000\u02d9\u02da\u0007\n\u0000\u0000\u02da\u02db\u0007\u0005\u0000"+ - "\u0000\u02db\u02dc\u0001\u0000\u0000\u0000\u02dc\u02dd\u0006\u0018\b\u0000"+ - "\u02ddD\u0001\u0000\u0000\u0000\u02de\u02df\u0004\u0019\b\u0000\u02df"+ - "\u02e0\u0007\u000f\u0000\u0000\u02e0\u02e1\u0007\u0007\u0000\u0000\u02e1"+ - "\u02e2\u0007\u0006\u0000\u0000\u02e2\u02e3\u0007\u0012\u0000\u0000\u02e3"+ - "\u02e4\u0001\u0000\u0000\u0000\u02e4\u02e5\u0006\u0019\f\u0000\u02e5F"+ - "\u0001\u0000\u0000\u0000\u02e6\u02e8\b\u0015\u0000\u0000\u02e7\u02e6\u0001"+ - "\u0000\u0000\u0000\u02e8\u02e9\u0001\u0000\u0000\u0000\u02e9\u02e7\u0001"+ - "\u0000\u0000\u0000\u02e9\u02ea\u0001\u0000\u0000\u0000\u02ea\u02eb\u0001"+ - "\u0000\u0000\u0000\u02eb\u02ec\u0006\u001a\u0000\u0000\u02ecH\u0001\u0000"+ - "\u0000\u0000\u02ed\u02ee\u0005/\u0000\u0000\u02ee\u02ef\u0005/\u0000\u0000"+ - "\u02ef\u02f3\u0001\u0000\u0000\u0000\u02f0\u02f2\b\u0016\u0000\u0000\u02f1"+ - "\u02f0\u0001\u0000\u0000\u0000\u02f2\u02f5\u0001\u0000\u0000\u0000\u02f3"+ - "\u02f1\u0001\u0000\u0000\u0000\u02f3\u02f4\u0001\u0000\u0000\u0000\u02f4"+ - "\u02f7\u0001\u0000\u0000\u0000\u02f5\u02f3\u0001\u0000\u0000\u0000\u02f6"+ - "\u02f8\u0005\r\u0000\u0000\u02f7\u02f6\u0001\u0000\u0000\u0000\u02f7\u02f8"+ - "\u0001\u0000\u0000\u0000\u02f8\u02fa\u0001\u0000\u0000\u0000\u02f9\u02fb"+ - "\u0005\n\u0000\u0000\u02fa\u02f9\u0001\u0000\u0000\u0000\u02fa\u02fb\u0001"+ - "\u0000\u0000\u0000\u02fb\u02fc\u0001\u0000\u0000\u0000\u02fc\u02fd\u0006"+ - "\u001b\r\u0000\u02fdJ\u0001\u0000\u0000\u0000\u02fe\u02ff\u0005/\u0000"+ - "\u0000\u02ff\u0300\u0005*\u0000\u0000\u0300\u0305\u0001\u0000\u0000\u0000"+ - "\u0301\u0304\u0003K\u001c\u0000\u0302\u0304\t\u0000\u0000\u0000\u0303"+ - "\u0301\u0001\u0000\u0000\u0000\u0303\u0302\u0001\u0000\u0000\u0000\u0304"+ - "\u0307\u0001\u0000\u0000\u0000\u0305\u0306\u0001\u0000\u0000\u0000\u0305"+ - "\u0303\u0001\u0000\u0000\u0000\u0306\u0308\u0001\u0000\u0000\u0000\u0307"+ - "\u0305\u0001\u0000\u0000\u0000\u0308\u0309\u0005*\u0000\u0000\u0309\u030a"+ - "\u0005/\u0000\u0000\u030a\u030b\u0001\u0000\u0000\u0000\u030b\u030c\u0006"+ - "\u001c\r\u0000\u030cL\u0001\u0000\u0000\u0000\u030d\u030f\u0007\u0017"+ - "\u0000\u0000\u030e\u030d\u0001\u0000\u0000\u0000\u030f\u0310\u0001\u0000"+ - "\u0000\u0000\u0310\u030e\u0001\u0000\u0000\u0000\u0310\u0311\u0001\u0000"+ - "\u0000\u0000\u0311\u0312\u0001\u0000\u0000\u0000\u0312\u0313\u0006\u001d"+ - "\r\u0000\u0313N\u0001\u0000\u0000\u0000\u0314\u0315\u0005|\u0000\u0000"+ - "\u0315\u0316\u0001\u0000\u0000\u0000\u0316\u0317\u0006\u001e\u000e\u0000"+ - "\u0317P\u0001\u0000\u0000\u0000\u0318\u0319\u0007\u0018\u0000\u0000\u0319"+ - "R\u0001\u0000\u0000\u0000\u031a\u031b\u0007\u0019\u0000\u0000\u031bT\u0001"+ - "\u0000\u0000\u0000\u031c\u031d\u0005\\\u0000\u0000\u031d\u031e\u0007\u001a"+ - "\u0000\u0000\u031eV\u0001\u0000\u0000\u0000\u031f\u0320\b\u001b\u0000"+ - "\u0000\u0320X\u0001\u0000\u0000\u0000\u0321\u0323\u0007\u0003\u0000\u0000"+ - "\u0322\u0324\u0007\u001c\u0000\u0000\u0323\u0322\u0001\u0000\u0000\u0000"+ - "\u0323\u0324\u0001\u0000\u0000\u0000\u0324\u0326\u0001\u0000\u0000\u0000"+ - "\u0325\u0327\u0003Q\u001f\u0000\u0326\u0325\u0001\u0000\u0000\u0000\u0327"+ - "\u0328\u0001\u0000\u0000\u0000\u0328\u0326\u0001\u0000\u0000\u0000\u0328"+ - "\u0329\u0001\u0000\u0000\u0000\u0329Z\u0001\u0000\u0000\u0000\u032a\u032b"+ - "\u0005@\u0000\u0000\u032b\\\u0001\u0000\u0000\u0000\u032c\u032d\u0005"+ - "`\u0000\u0000\u032d^\u0001\u0000\u0000\u0000\u032e\u0332\b\u001d\u0000"+ - "\u0000\u032f\u0330\u0005`\u0000\u0000\u0330\u0332\u0005`\u0000\u0000\u0331"+ - "\u032e\u0001\u0000\u0000\u0000\u0331\u032f\u0001\u0000\u0000\u0000\u0332"+ - "`\u0001\u0000\u0000\u0000\u0333\u0334\u0005_\u0000\u0000\u0334b\u0001"+ - "\u0000\u0000\u0000\u0335\u0339\u0003S \u0000\u0336\u0339\u0003Q\u001f"+ - "\u0000\u0337\u0339\u0003a\'\u0000\u0338\u0335\u0001\u0000\u0000\u0000"+ - "\u0338\u0336\u0001\u0000\u0000\u0000\u0338\u0337\u0001\u0000\u0000\u0000"+ - "\u0339d\u0001\u0000\u0000\u0000\u033a\u033f\u0005\"\u0000\u0000\u033b"+ - "\u033e\u0003U!\u0000\u033c\u033e\u0003W\"\u0000\u033d\u033b\u0001\u0000"+ - "\u0000\u0000\u033d\u033c\u0001\u0000\u0000\u0000\u033e\u0341\u0001\u0000"+ - "\u0000\u0000\u033f\u033d\u0001\u0000\u0000\u0000\u033f\u0340\u0001\u0000"+ - "\u0000\u0000\u0340\u0342\u0001\u0000\u0000\u0000\u0341\u033f\u0001\u0000"+ - "\u0000\u0000\u0342\u0358\u0005\"\u0000\u0000\u0343\u0344\u0005\"\u0000"+ - "\u0000\u0344\u0345\u0005\"\u0000\u0000\u0345\u0346\u0005\"\u0000\u0000"+ - "\u0346\u034a\u0001\u0000\u0000\u0000\u0347\u0349\b\u0016\u0000\u0000\u0348"+ - "\u0347\u0001\u0000\u0000\u0000\u0349\u034c\u0001\u0000\u0000\u0000\u034a"+ - "\u034b\u0001\u0000\u0000\u0000\u034a\u0348\u0001\u0000\u0000\u0000\u034b"+ - "\u034d\u0001\u0000\u0000\u0000\u034c\u034a\u0001\u0000\u0000\u0000\u034d"+ - "\u034e\u0005\"\u0000\u0000\u034e\u034f\u0005\"\u0000\u0000\u034f\u0350"+ - "\u0005\"\u0000\u0000\u0350\u0352\u0001\u0000\u0000\u0000\u0351\u0353\u0005"+ - "\"\u0000\u0000\u0352\u0351\u0001\u0000\u0000\u0000\u0352\u0353\u0001\u0000"+ - "\u0000\u0000\u0353\u0355\u0001\u0000\u0000\u0000\u0354\u0356\u0005\"\u0000"+ - "\u0000\u0355\u0354\u0001\u0000\u0000\u0000\u0355\u0356\u0001\u0000\u0000"+ - "\u0000\u0356\u0358\u0001\u0000\u0000\u0000\u0357\u033a\u0001\u0000\u0000"+ - "\u0000\u0357\u0343\u0001\u0000\u0000\u0000\u0358f\u0001\u0000\u0000\u0000"+ - "\u0359\u035b\u0003Q\u001f\u0000\u035a\u0359\u0001\u0000\u0000\u0000\u035b"+ - "\u035c\u0001\u0000\u0000\u0000\u035c\u035a\u0001\u0000\u0000\u0000\u035c"+ - "\u035d\u0001\u0000\u0000\u0000\u035dh\u0001\u0000\u0000\u0000\u035e\u0360"+ - "\u0003Q\u001f\u0000\u035f\u035e\u0001\u0000\u0000\u0000\u0360\u0361\u0001"+ - "\u0000\u0000\u0000\u0361\u035f\u0001\u0000\u0000\u0000\u0361\u0362\u0001"+ - "\u0000\u0000\u0000\u0362\u0363\u0001\u0000\u0000\u0000\u0363\u0367\u0003"+ - "{4\u0000\u0364\u0366\u0003Q\u001f\u0000\u0365\u0364\u0001\u0000\u0000"+ - "\u0000\u0366\u0369\u0001\u0000\u0000\u0000\u0367\u0365\u0001\u0000\u0000"+ - "\u0000\u0367\u0368\u0001\u0000\u0000\u0000\u0368\u0389\u0001\u0000\u0000"+ - "\u0000\u0369\u0367\u0001\u0000\u0000\u0000\u036a\u036c\u0003{4\u0000\u036b"+ - "\u036d\u0003Q\u001f\u0000\u036c\u036b\u0001\u0000\u0000\u0000\u036d\u036e"+ - "\u0001\u0000\u0000\u0000\u036e\u036c\u0001\u0000\u0000\u0000\u036e\u036f"+ - "\u0001\u0000\u0000\u0000\u036f\u0389\u0001\u0000\u0000\u0000\u0370\u0372"+ - "\u0003Q\u001f\u0000\u0371\u0370\u0001\u0000\u0000\u0000\u0372\u0373\u0001"+ - "\u0000\u0000\u0000\u0373\u0371\u0001\u0000\u0000\u0000\u0373\u0374\u0001"+ - "\u0000\u0000\u0000\u0374\u037c\u0001\u0000\u0000\u0000\u0375\u0379\u0003"+ - "{4\u0000\u0376\u0378\u0003Q\u001f\u0000\u0377\u0376\u0001\u0000\u0000"+ - "\u0000\u0378\u037b\u0001\u0000\u0000\u0000\u0379\u0377\u0001\u0000\u0000"+ - "\u0000\u0379\u037a\u0001\u0000\u0000\u0000\u037a\u037d\u0001\u0000\u0000"+ - "\u0000\u037b\u0379\u0001\u0000\u0000\u0000\u037c\u0375\u0001\u0000\u0000"+ - "\u0000\u037c\u037d\u0001\u0000\u0000\u0000\u037d\u037e\u0001\u0000\u0000"+ - "\u0000\u037e\u037f\u0003Y#\u0000\u037f\u0389\u0001\u0000\u0000\u0000\u0380"+ - "\u0382\u0003{4\u0000\u0381\u0383\u0003Q\u001f\u0000\u0382\u0381\u0001"+ - "\u0000\u0000\u0000\u0383\u0384\u0001\u0000\u0000\u0000\u0384\u0382\u0001"+ - "\u0000\u0000\u0000\u0384\u0385\u0001\u0000\u0000\u0000\u0385\u0386\u0001"+ - "\u0000\u0000\u0000\u0386\u0387\u0003Y#\u0000\u0387\u0389\u0001\u0000\u0000"+ - "\u0000\u0388\u035f\u0001\u0000\u0000\u0000\u0388\u036a\u0001\u0000\u0000"+ - "\u0000\u0388\u0371\u0001\u0000\u0000\u0000\u0388\u0380\u0001\u0000\u0000"+ - "\u0000\u0389j\u0001\u0000\u0000\u0000\u038a\u038b\u0007\u001e\u0000\u0000"+ - "\u038b\u038c\u0007\u001f\u0000\u0000\u038cl\u0001\u0000\u0000\u0000\u038d"+ - "\u038e\u0007\f\u0000\u0000\u038e\u038f\u0007\t\u0000\u0000\u038f\u0390"+ - "\u0007\u0000\u0000\u0000\u0390n\u0001\u0000\u0000\u0000\u0391\u0392\u0007"+ - "\f\u0000\u0000\u0392\u0393\u0007\u0002\u0000\u0000\u0393\u0394\u0007\u0004"+ - "\u0000\u0000\u0394p\u0001\u0000\u0000\u0000\u0395\u0396\u0005=\u0000\u0000"+ - "\u0396r\u0001\u0000\u0000\u0000\u0397\u0398\u0005:\u0000\u0000\u0398\u0399"+ - "\u0005:\u0000\u0000\u0399t\u0001\u0000\u0000\u0000\u039a\u039b\u0005:"+ - "\u0000\u0000\u039bv\u0001\u0000\u0000\u0000\u039c\u039d\u0005,\u0000\u0000"+ - "\u039dx\u0001\u0000\u0000\u0000\u039e\u039f\u0007\u0000\u0000\u0000\u039f"+ - "\u03a0\u0007\u0003\u0000\u0000\u03a0\u03a1\u0007\u0002\u0000\u0000\u03a1"+ - "\u03a2\u0007\u0004\u0000\u0000\u03a2z\u0001\u0000\u0000\u0000\u03a3\u03a4"+ - "\u0005.\u0000\u0000\u03a4|\u0001\u0000\u0000\u0000\u03a5\u03a6\u0007\u000f"+ - "\u0000\u0000\u03a6\u03a7\u0007\f\u0000\u0000\u03a7\u03a8\u0007\r\u0000"+ - "\u0000\u03a8\u03a9\u0007\u0002\u0000\u0000\u03a9\u03aa\u0007\u0003\u0000"+ - "\u0000\u03aa~\u0001\u0000\u0000\u0000\u03ab\u03ac\u0007\u000f\u0000\u0000"+ - "\u03ac\u03ad\u0007\u0001\u0000\u0000\u03ad\u03ae\u0007\u0006\u0000\u0000"+ - "\u03ae\u03af\u0007\u0002\u0000\u0000\u03af\u03b0\u0007\u0005\u0000\u0000"+ - "\u03b0\u0080\u0001\u0000\u0000\u0000\u03b1\u03b2\u0007\u0001\u0000\u0000"+ - "\u03b2\u03b3\u0007\t\u0000\u0000\u03b3\u0082\u0001\u0000\u0000\u0000\u03b4"+ - "\u03b5\u0007\u0001\u0000\u0000\u03b5\u03b6\u0007\u0002\u0000\u0000\u03b6"+ - "\u0084\u0001\u0000\u0000\u0000\u03b7\u03b8\u0007\r\u0000\u0000\u03b8\u03b9"+ - "\u0007\f\u0000\u0000\u03b9\u03ba\u0007\u0002\u0000\u0000\u03ba\u03bb\u0007"+ - "\u0005\u0000\u0000\u03bb\u0086\u0001\u0000\u0000\u0000\u03bc\u03bd\u0007"+ - "\r\u0000\u0000\u03bd\u03be\u0007\u0001\u0000\u0000\u03be\u03bf\u0007\u0012"+ - "\u0000\u0000\u03bf\u03c0\u0007\u0003\u0000\u0000\u03c0\u0088\u0001\u0000"+ - "\u0000\u0000\u03c1\u03c2\u0005(\u0000\u0000\u03c2\u008a\u0001\u0000\u0000"+ - "\u0000\u03c3\u03c4\u0007\t\u0000\u0000\u03c4\u03c5\u0007\u0007\u0000\u0000"+ - "\u03c5\u03c6\u0007\u0005\u0000\u0000\u03c6\u008c\u0001\u0000\u0000\u0000"+ - "\u03c7\u03c8\u0007\t\u0000\u0000\u03c8\u03c9\u0007\u0014\u0000\u0000\u03c9"+ - "\u03ca\u0007\r\u0000\u0000\u03ca\u03cb\u0007\r\u0000\u0000\u03cb\u008e"+ - "\u0001\u0000\u0000\u0000\u03cc\u03cd\u0007\t\u0000\u0000\u03cd\u03ce\u0007"+ - "\u0014\u0000\u0000\u03ce\u03cf\u0007\r\u0000\u0000\u03cf\u03d0\u0007\r"+ - "\u0000\u0000\u03d0\u03d1\u0007\u0002\u0000\u0000\u03d1\u0090\u0001\u0000"+ - "\u0000\u0000\u03d2\u03d3\u0007\u0007\u0000\u0000\u03d3\u03d4\u0007\u0006"+ - "\u0000\u0000\u03d4\u0092\u0001\u0000\u0000\u0000\u03d5\u03d6\u0005?\u0000"+ - "\u0000\u03d6\u0094\u0001\u0000\u0000\u0000\u03d7\u03d8\u0007\u0006\u0000"+ - "\u0000\u03d8\u03d9\u0007\r\u0000\u0000\u03d9\u03da\u0007\u0001\u0000\u0000"+ - "\u03da\u03db\u0007\u0012\u0000\u0000\u03db\u03dc\u0007\u0003\u0000\u0000"+ - "\u03dc\u0096\u0001\u0000\u0000\u0000\u03dd\u03de\u0005)\u0000\u0000\u03de"+ - "\u0098\u0001\u0000\u0000\u0000\u03df\u03e0\u0007\u0005\u0000\u0000\u03e0"+ - "\u03e1\u0007\u0006\u0000\u0000\u03e1\u03e2\u0007\u0014\u0000\u0000\u03e2"+ - "\u03e3\u0007\u0003\u0000\u0000\u03e3\u009a\u0001\u0000\u0000\u0000\u03e4"+ - "\u03e5\u0005=\u0000\u0000\u03e5\u03e6\u0005=\u0000\u0000\u03e6\u009c\u0001"+ - "\u0000\u0000\u0000\u03e7\u03e8\u0005=\u0000\u0000\u03e8\u03e9\u0005~\u0000"+ - "\u0000\u03e9\u009e\u0001\u0000\u0000\u0000\u03ea\u03eb\u0005!\u0000\u0000"+ - "\u03eb\u03ec\u0005=\u0000\u0000\u03ec\u00a0\u0001\u0000\u0000\u0000\u03ed"+ - "\u03ee\u0005<\u0000\u0000\u03ee\u00a2\u0001\u0000\u0000\u0000\u03ef\u03f0"+ - "\u0005<\u0000\u0000\u03f0\u03f1\u0005=\u0000\u0000\u03f1\u00a4\u0001\u0000"+ - "\u0000\u0000\u03f2\u03f3\u0005>\u0000\u0000\u03f3\u00a6\u0001\u0000\u0000"+ - "\u0000\u03f4\u03f5\u0005>\u0000\u0000\u03f5\u03f6\u0005=\u0000\u0000\u03f6"+ - "\u00a8\u0001\u0000\u0000\u0000\u03f7\u03f8\u0005+\u0000\u0000\u03f8\u00aa"+ - "\u0001\u0000\u0000\u0000\u03f9\u03fa\u0005-\u0000\u0000\u03fa\u00ac\u0001"+ - "\u0000\u0000\u0000\u03fb\u03fc\u0005*\u0000\u0000\u03fc\u00ae\u0001\u0000"+ - "\u0000\u0000\u03fd\u03fe\u0005/\u0000\u0000\u03fe\u00b0\u0001\u0000\u0000"+ - "\u0000\u03ff\u0400\u0005%\u0000\u0000\u0400\u00b2\u0001\u0000\u0000\u0000"+ - "\u0401\u0402\u0005{\u0000\u0000\u0402\u00b4\u0001\u0000\u0000\u0000\u0403"+ - "\u0404\u0005}\u0000\u0000\u0404\u00b6\u0001\u0000\u0000\u0000\u0405\u0406"+ - "\u00031\u000f\u0000\u0406\u0407\u0001\u0000\u0000\u0000\u0407\u0408\u0006"+ - "R\u000f\u0000\u0408\u00b8\u0001\u0000\u0000\u0000\u0409\u040a\u0004S\t"+ - "\u0000\u040a\u040b\u0003-\r\u0000\u040b\u040c\u0001\u0000\u0000\u0000"+ - "\u040c\u040d\u0006S\u0010\u0000\u040d\u00ba\u0001\u0000\u0000\u0000\u040e"+ - "\u040f\u0004T\n\u0000\u040f\u0410\u0003#\b\u0000\u0410\u0411\u0001\u0000"+ - "\u0000\u0000\u0411\u0412\u0006T\u0011\u0000\u0412\u00bc\u0001\u0000\u0000"+ - "\u0000\u0413\u0416\u0003\u0093@\u0000\u0414\u0417\u0003S \u0000\u0415"+ - "\u0417\u0003a\'\u0000\u0416\u0414\u0001\u0000\u0000\u0000\u0416\u0415"+ - "\u0001\u0000\u0000\u0000\u0417\u041b\u0001\u0000\u0000\u0000\u0418\u041a"+ - "\u0003c(\u0000\u0419\u0418\u0001\u0000\u0000\u0000\u041a\u041d\u0001\u0000"+ - "\u0000\u0000\u041b\u0419\u0001\u0000\u0000\u0000\u041b\u041c\u0001\u0000"+ - "\u0000\u0000\u041c\u0425\u0001\u0000\u0000\u0000\u041d\u041b\u0001\u0000"+ - "\u0000\u0000\u041e\u0420\u0003\u0093@\u0000\u041f\u0421\u0003Q\u001f\u0000"+ - "\u0420\u041f\u0001\u0000\u0000\u0000\u0421\u0422\u0001\u0000\u0000\u0000"+ - "\u0422\u0420\u0001\u0000\u0000\u0000\u0422\u0423\u0001\u0000\u0000\u0000"+ - "\u0423\u0425\u0001\u0000\u0000\u0000\u0424\u0413\u0001\u0000\u0000\u0000"+ - "\u0424\u041e\u0001\u0000\u0000\u0000\u0425\u00be\u0001\u0000\u0000\u0000"+ - "\u0426\u0427\u0005[\u0000\u0000\u0427\u0428\u0001\u0000\u0000\u0000\u0428"+ - "\u0429\u0006V\u0000\u0000\u0429\u042a\u0006V\u0000\u0000\u042a\u00c0\u0001"+ - "\u0000\u0000\u0000\u042b\u042c\u0005]\u0000\u0000\u042c\u042d\u0001\u0000"+ - "\u0000\u0000\u042d\u042e\u0006W\u000e\u0000\u042e\u042f\u0006W\u000e\u0000"+ - "\u042f\u00c2\u0001\u0000\u0000\u0000\u0430\u0434\u0003S \u0000\u0431\u0433"+ - "\u0003c(\u0000\u0432\u0431\u0001\u0000\u0000\u0000\u0433\u0436\u0001\u0000"+ - "\u0000\u0000\u0434\u0432\u0001\u0000\u0000\u0000\u0434\u0435\u0001\u0000"+ - "\u0000\u0000\u0435\u0441\u0001\u0000\u0000\u0000\u0436\u0434\u0001\u0000"+ - "\u0000\u0000\u0437\u043a\u0003a\'\u0000\u0438\u043a\u0003[$\u0000\u0439"+ - "\u0437\u0001\u0000\u0000\u0000\u0439\u0438\u0001\u0000\u0000\u0000\u043a"+ - "\u043c\u0001\u0000\u0000\u0000\u043b\u043d\u0003c(\u0000\u043c\u043b\u0001"+ - "\u0000\u0000\u0000\u043d\u043e\u0001\u0000\u0000\u0000\u043e\u043c\u0001"+ - "\u0000\u0000\u0000\u043e\u043f\u0001\u0000\u0000\u0000\u043f\u0441\u0001"+ - "\u0000\u0000\u0000\u0440\u0430\u0001\u0000\u0000\u0000\u0440\u0439\u0001"+ - "\u0000\u0000\u0000\u0441\u00c4\u0001\u0000\u0000\u0000\u0442\u0444\u0003"+ - "]%\u0000\u0443\u0445\u0003_&\u0000\u0444\u0443\u0001\u0000\u0000\u0000"+ - "\u0445\u0446\u0001\u0000\u0000\u0000\u0446\u0444\u0001\u0000\u0000\u0000"+ - "\u0446\u0447\u0001\u0000\u0000\u0000\u0447\u0448\u0001\u0000\u0000\u0000"+ - "\u0448\u0449\u0003]%\u0000\u0449\u00c6\u0001\u0000\u0000\u0000\u044a\u044b"+ - "\u0003\u00c5Y\u0000\u044b\u00c8\u0001\u0000\u0000\u0000\u044c\u044d\u0003"+ - "I\u001b\u0000\u044d\u044e\u0001\u0000\u0000\u0000\u044e\u044f\u0006[\r"+ - "\u0000\u044f\u00ca\u0001\u0000\u0000\u0000\u0450\u0451\u0003K\u001c\u0000"+ - "\u0451\u0452\u0001\u0000\u0000\u0000\u0452\u0453\u0006\\\r\u0000\u0453"+ - "\u00cc\u0001\u0000\u0000\u0000\u0454\u0455\u0003M\u001d\u0000\u0455\u0456"+ - "\u0001\u0000\u0000\u0000\u0456\u0457\u0006]\r\u0000\u0457\u00ce\u0001"+ - "\u0000\u0000\u0000\u0458\u0459\u0003\u00bfV\u0000\u0459\u045a\u0001\u0000"+ - "\u0000\u0000\u045a\u045b\u0006^\u0012\u0000\u045b\u045c\u0006^\u0013\u0000"+ - "\u045c\u00d0\u0001\u0000\u0000\u0000\u045d\u045e\u0003O\u001e\u0000\u045e"+ - "\u045f\u0001\u0000\u0000\u0000\u045f\u0460\u0006_\u0014\u0000\u0460\u0461"+ - "\u0006_\u000e\u0000\u0461\u00d2\u0001\u0000\u0000\u0000\u0462\u0463\u0003"+ - "M\u001d\u0000\u0463\u0464\u0001\u0000\u0000\u0000\u0464\u0465\u0006`\r"+ - "\u0000\u0465\u00d4\u0001\u0000\u0000\u0000\u0466\u0467\u0003I\u001b\u0000"+ - "\u0467\u0468\u0001\u0000\u0000\u0000\u0468\u0469\u0006a\r\u0000\u0469"+ - "\u00d6\u0001\u0000\u0000\u0000\u046a\u046b\u0003K\u001c\u0000\u046b\u046c"+ - "\u0001\u0000\u0000\u0000\u046c\u046d\u0006b\r\u0000\u046d\u00d8\u0001"+ - "\u0000\u0000\u0000\u046e\u046f\u0003O\u001e\u0000\u046f\u0470\u0001\u0000"+ - "\u0000\u0000\u0470\u0471\u0006c\u0014\u0000\u0471\u0472\u0006c\u000e\u0000"+ - "\u0472\u00da\u0001\u0000\u0000\u0000\u0473\u0474\u0003\u00bfV\u0000\u0474"+ - "\u0475\u0001\u0000\u0000\u0000\u0475\u0476\u0006d\u0012\u0000\u0476\u00dc"+ - "\u0001\u0000\u0000\u0000\u0477\u0478\u0003\u00c1W\u0000\u0478\u0479\u0001"+ - "\u0000\u0000\u0000\u0479\u047a\u0006e\u0015\u0000\u047a\u00de\u0001\u0000"+ - "\u0000\u0000\u047b\u047c\u0003u1\u0000\u047c\u047d\u0001\u0000\u0000\u0000"+ - "\u047d\u047e\u0006f\u0016\u0000\u047e\u00e0\u0001\u0000\u0000\u0000\u047f"+ - "\u0480\u0003w2\u0000\u0480\u0481\u0001\u0000\u0000\u0000\u0481\u0482\u0006"+ - "g\u0017\u0000\u0482\u00e2\u0001\u0000\u0000\u0000\u0483\u0484\u0003q/"+ - "\u0000\u0484\u0485\u0001\u0000\u0000\u0000\u0485\u0486\u0006h\u0018\u0000"+ - "\u0486\u00e4\u0001\u0000\u0000\u0000\u0487\u0488\u0007\u0010\u0000\u0000"+ - "\u0488\u0489\u0007\u0003\u0000\u0000\u0489\u048a\u0007\u0005\u0000\u0000"+ - "\u048a\u048b\u0007\f\u0000\u0000\u048b\u048c\u0007\u0000\u0000\u0000\u048c"+ - "\u048d\u0007\f\u0000\u0000\u048d\u048e\u0007\u0005\u0000\u0000\u048e\u048f"+ - "\u0007\f\u0000\u0000\u048f\u00e6\u0001\u0000\u0000\u0000\u0490\u0494\b"+ - " \u0000\u0000\u0491\u0492\u0005/\u0000\u0000\u0492\u0494\b!\u0000\u0000"+ - "\u0493\u0490\u0001\u0000\u0000\u0000\u0493\u0491\u0001\u0000\u0000\u0000"+ - "\u0494\u00e8\u0001\u0000\u0000\u0000\u0495\u0497\u0003\u00e7j\u0000\u0496"+ - "\u0495\u0001\u0000\u0000\u0000\u0497\u0498\u0001\u0000\u0000\u0000\u0498"+ - "\u0496\u0001\u0000\u0000\u0000\u0498\u0499\u0001\u0000\u0000\u0000\u0499"+ - "\u00ea\u0001\u0000\u0000\u0000\u049a\u049b\u0003\u00e9k\u0000\u049b\u049c"+ - "\u0001\u0000\u0000\u0000\u049c\u049d\u0006l\u0019\u0000\u049d\u00ec\u0001"+ - "\u0000\u0000\u0000\u049e\u049f\u0003e)\u0000\u049f\u04a0\u0001\u0000\u0000"+ - "\u0000\u04a0\u04a1\u0006m\u001a\u0000\u04a1\u00ee\u0001\u0000\u0000\u0000"+ - "\u04a2\u04a3\u0003I\u001b\u0000\u04a3\u04a4\u0001\u0000\u0000\u0000\u04a4"+ - "\u04a5\u0006n\r\u0000\u04a5\u00f0\u0001\u0000\u0000\u0000\u04a6\u04a7"+ - "\u0003K\u001c\u0000\u04a7\u04a8\u0001\u0000\u0000\u0000\u04a8\u04a9\u0006"+ - "o\r\u0000\u04a9\u00f2\u0001\u0000\u0000\u0000\u04aa\u04ab\u0003M\u001d"+ - "\u0000\u04ab\u04ac\u0001\u0000\u0000\u0000\u04ac\u04ad\u0006p\r\u0000"+ - "\u04ad\u00f4\u0001\u0000\u0000\u0000\u04ae\u04af\u0003O\u001e\u0000\u04af"+ - "\u04b0\u0001\u0000\u0000\u0000\u04b0\u04b1\u0006q\u0014\u0000\u04b1\u04b2"+ - "\u0006q\u000e\u0000\u04b2\u00f6\u0001\u0000\u0000\u0000\u04b3\u04b4\u0003"+ - "{4\u0000\u04b4\u04b5\u0001\u0000\u0000\u0000\u04b5\u04b6\u0006r\u001b"+ - "\u0000\u04b6\u00f8\u0001\u0000\u0000\u0000\u04b7\u04b8\u0003w2\u0000\u04b8"+ - "\u04b9\u0001\u0000\u0000\u0000\u04b9\u04ba\u0006s\u0017\u0000\u04ba\u00fa"+ - "\u0001\u0000\u0000\u0000\u04bb\u04bc\u0003\u0093@\u0000\u04bc\u04bd\u0001"+ - "\u0000\u0000\u0000\u04bd\u04be\u0006t\u001c\u0000\u04be\u00fc\u0001\u0000"+ - "\u0000\u0000\u04bf\u04c0\u0003\u00bdU\u0000\u04c0\u04c1\u0001\u0000\u0000"+ - "\u0000\u04c1\u04c2\u0006u\u001d\u0000\u04c2\u00fe\u0001\u0000\u0000\u0000"+ - "\u04c3\u04c8\u0003S \u0000\u04c4\u04c8\u0003Q\u001f\u0000\u04c5\u04c8"+ - "\u0003a\'\u0000\u04c6\u04c8\u0003\u00adM\u0000\u04c7\u04c3\u0001\u0000"+ - "\u0000\u0000\u04c7\u04c4\u0001\u0000\u0000\u0000\u04c7\u04c5\u0001\u0000"+ - "\u0000\u0000\u04c7\u04c6\u0001\u0000\u0000\u0000\u04c8\u0100\u0001\u0000"+ - "\u0000\u0000\u04c9\u04cc\u0003S \u0000\u04ca\u04cc\u0003\u00adM\u0000"+ - "\u04cb\u04c9\u0001\u0000\u0000\u0000\u04cb\u04ca\u0001\u0000\u0000\u0000"+ - "\u04cc\u04d0\u0001\u0000\u0000\u0000\u04cd\u04cf\u0003\u00ffv\u0000\u04ce"+ - "\u04cd\u0001\u0000\u0000\u0000\u04cf\u04d2\u0001\u0000\u0000\u0000\u04d0"+ - "\u04ce\u0001\u0000\u0000\u0000\u04d0\u04d1\u0001\u0000\u0000\u0000\u04d1"+ - "\u04dd\u0001\u0000\u0000\u0000\u04d2\u04d0\u0001\u0000\u0000\u0000\u04d3"+ - "\u04d6\u0003a\'\u0000\u04d4\u04d6\u0003[$\u0000\u04d5\u04d3\u0001\u0000"+ - "\u0000\u0000\u04d5\u04d4\u0001\u0000\u0000\u0000\u04d6\u04d8\u0001\u0000"+ - "\u0000\u0000\u04d7\u04d9\u0003\u00ffv\u0000\u04d8\u04d7\u0001\u0000\u0000"+ - "\u0000\u04d9\u04da\u0001\u0000\u0000\u0000\u04da\u04d8\u0001\u0000\u0000"+ - "\u0000\u04da\u04db\u0001\u0000\u0000\u0000\u04db\u04dd\u0001\u0000\u0000"+ - "\u0000\u04dc\u04cb\u0001\u0000\u0000\u0000\u04dc\u04d5\u0001\u0000\u0000"+ - "\u0000\u04dd\u0102\u0001\u0000\u0000\u0000\u04de\u04e1\u0003\u0101w\u0000"+ - "\u04df\u04e1\u0003\u00c5Y\u0000\u04e0\u04de\u0001\u0000\u0000\u0000\u04e0"+ - "\u04df\u0001\u0000\u0000\u0000\u04e1\u04e2\u0001\u0000\u0000\u0000\u04e2"+ - "\u04e0\u0001\u0000\u0000\u0000\u04e2\u04e3\u0001\u0000\u0000\u0000\u04e3"+ - "\u0104\u0001\u0000\u0000\u0000\u04e4\u04e5\u0003I\u001b\u0000\u04e5\u04e6"+ - "\u0001\u0000\u0000\u0000\u04e6\u04e7\u0006y\r\u0000\u04e7\u0106\u0001"+ - "\u0000\u0000\u0000\u04e8\u04e9\u0003K\u001c\u0000\u04e9\u04ea\u0001\u0000"+ - "\u0000\u0000\u04ea\u04eb\u0006z\r\u0000\u04eb\u0108\u0001\u0000\u0000"+ - "\u0000\u04ec\u04ed\u0003M\u001d\u0000\u04ed\u04ee\u0001\u0000\u0000\u0000"+ - "\u04ee\u04ef\u0006{\r\u0000\u04ef\u010a\u0001\u0000\u0000\u0000\u04f0"+ - "\u04f1\u0003O\u001e\u0000\u04f1\u04f2\u0001\u0000\u0000\u0000\u04f2\u04f3"+ - "\u0006|\u0014\u0000\u04f3\u04f4\u0006|\u000e\u0000\u04f4\u010c\u0001\u0000"+ - "\u0000\u0000\u04f5\u04f6\u0003q/\u0000\u04f6\u04f7\u0001\u0000\u0000\u0000"+ - "\u04f7\u04f8\u0006}\u0018\u0000\u04f8\u010e\u0001\u0000\u0000\u0000\u04f9"+ - "\u04fa\u0003w2\u0000\u04fa\u04fb\u0001\u0000\u0000\u0000\u04fb\u04fc\u0006"+ - "~\u0017\u0000\u04fc\u0110\u0001\u0000\u0000\u0000\u04fd\u04fe\u0003{4"+ - "\u0000\u04fe\u04ff\u0001\u0000\u0000\u0000\u04ff\u0500\u0006\u007f\u001b"+ - "\u0000\u0500\u0112\u0001\u0000\u0000\u0000\u0501\u0502\u0003\u0093@\u0000"+ - "\u0502\u0503\u0001\u0000\u0000\u0000\u0503\u0504\u0006\u0080\u001c\u0000"+ - "\u0504\u0114\u0001\u0000\u0000\u0000\u0505\u0506\u0003\u00bdU\u0000\u0506"+ - "\u0507\u0001\u0000\u0000\u0000\u0507\u0508\u0006\u0081\u001d\u0000\u0508"+ - "\u0116\u0001\u0000\u0000\u0000\u0509\u050a\u0007\f\u0000\u0000\u050a\u050b"+ - "\u0007\u0002\u0000\u0000\u050b\u0118\u0001\u0000\u0000\u0000\u050c\u050d"+ - "\u0003\u0103x\u0000\u050d\u050e\u0001\u0000\u0000\u0000\u050e\u050f\u0006"+ - "\u0083\u001e\u0000\u050f\u011a\u0001\u0000\u0000\u0000\u0510\u0511\u0003"+ - "I\u001b\u0000\u0511\u0512\u0001\u0000\u0000\u0000\u0512\u0513\u0006\u0084"+ - "\r\u0000\u0513\u011c\u0001\u0000\u0000\u0000\u0514\u0515\u0003K\u001c"+ - "\u0000\u0515\u0516\u0001\u0000\u0000\u0000\u0516\u0517\u0006\u0085\r\u0000"+ - "\u0517\u011e\u0001\u0000\u0000\u0000\u0518\u0519\u0003M\u001d\u0000\u0519"+ - "\u051a\u0001\u0000\u0000\u0000\u051a\u051b\u0006\u0086\r\u0000\u051b\u0120"+ - "\u0001\u0000\u0000\u0000\u051c\u051d\u0003O\u001e\u0000\u051d\u051e\u0001"+ - "\u0000\u0000\u0000\u051e\u051f\u0006\u0087\u0014\u0000\u051f\u0520\u0006"+ - "\u0087\u000e\u0000\u0520\u0122\u0001\u0000\u0000\u0000\u0521\u0522\u0003"+ - "\u00bfV\u0000\u0522\u0523\u0001\u0000\u0000\u0000\u0523\u0524\u0006\u0088"+ - "\u0012\u0000\u0524\u0525\u0006\u0088\u001f\u0000\u0525\u0124\u0001\u0000"+ - "\u0000\u0000\u0526\u0527\u0007\u0007\u0000\u0000\u0527\u0528\u0007\t\u0000"+ - "\u0000\u0528\u0529\u0001\u0000\u0000\u0000\u0529\u052a\u0006\u0089 \u0000"+ - "\u052a\u0126\u0001\u0000\u0000\u0000\u052b\u052c\u0007\u0013\u0000\u0000"+ - "\u052c\u052d\u0007\u0001\u0000\u0000\u052d\u052e\u0007\u0005\u0000\u0000"+ - "\u052e\u052f\u0007\n\u0000\u0000\u052f\u0530\u0001\u0000\u0000\u0000\u0530"+ - "\u0531\u0006\u008a \u0000\u0531\u0128\u0001\u0000\u0000\u0000\u0532\u0533"+ - "\b\"\u0000\u0000\u0533\u012a\u0001\u0000\u0000\u0000\u0534\u0536\u0003"+ - "\u0129\u008b\u0000\u0535\u0534\u0001\u0000\u0000\u0000\u0536\u0537\u0001"+ - "\u0000\u0000\u0000\u0537\u0535\u0001\u0000\u0000\u0000\u0537\u0538\u0001"+ - "\u0000\u0000\u0000\u0538\u0539\u0001\u0000\u0000\u0000\u0539\u053a\u0003"+ - "u1\u0000\u053a\u053c\u0001\u0000\u0000\u0000\u053b\u0535\u0001\u0000\u0000"+ - "\u0000\u053b\u053c\u0001\u0000\u0000\u0000\u053c\u053e\u0001\u0000\u0000"+ - "\u0000\u053d\u053f\u0003\u0129\u008b\u0000\u053e\u053d\u0001\u0000\u0000"+ - "\u0000\u053f\u0540\u0001\u0000\u0000\u0000\u0540\u053e\u0001\u0000\u0000"+ - "\u0000\u0540\u0541\u0001\u0000\u0000\u0000\u0541\u012c\u0001\u0000\u0000"+ - "\u0000\u0542\u0543\u0003\u012b\u008c\u0000\u0543\u0544\u0001\u0000\u0000"+ - "\u0000\u0544\u0545\u0006\u008d!\u0000\u0545\u012e\u0001\u0000\u0000\u0000"+ - "\u0546\u0547\u0003I\u001b\u0000\u0547\u0548\u0001\u0000\u0000\u0000\u0548"+ - "\u0549\u0006\u008e\r\u0000\u0549\u0130\u0001\u0000\u0000\u0000\u054a\u054b"+ - "\u0003K\u001c\u0000\u054b\u054c\u0001\u0000\u0000\u0000\u054c\u054d\u0006"+ - "\u008f\r\u0000\u054d\u0132\u0001\u0000\u0000\u0000\u054e\u054f\u0003M"+ - "\u001d\u0000\u054f\u0550\u0001\u0000\u0000\u0000\u0550\u0551\u0006\u0090"+ - "\r\u0000\u0551\u0134\u0001\u0000\u0000\u0000\u0552\u0553\u0003O\u001e"+ - "\u0000\u0553\u0554\u0001\u0000\u0000\u0000\u0554\u0555\u0006\u0091\u0014"+ - "\u0000\u0555\u0556\u0006\u0091\u000e\u0000\u0556\u0557\u0006\u0091\u000e"+ - "\u0000\u0557\u0136\u0001\u0000\u0000\u0000\u0558\u0559\u0003q/\u0000\u0559"+ - "\u055a\u0001\u0000\u0000\u0000\u055a\u055b\u0006\u0092\u0018\u0000\u055b"+ - "\u0138\u0001\u0000\u0000\u0000\u055c\u055d\u0003w2\u0000\u055d\u055e\u0001"+ - "\u0000\u0000\u0000\u055e\u055f\u0006\u0093\u0017\u0000\u055f\u013a\u0001"+ - "\u0000\u0000\u0000\u0560\u0561\u0003{4\u0000\u0561\u0562\u0001\u0000\u0000"+ - "\u0000\u0562\u0563\u0006\u0094\u001b\u0000\u0563\u013c\u0001\u0000\u0000"+ - "\u0000\u0564\u0565\u0003\u0127\u008a\u0000\u0565\u0566\u0001\u0000\u0000"+ - "\u0000\u0566\u0567\u0006\u0095\"\u0000\u0567\u013e\u0001\u0000\u0000\u0000"+ - "\u0568\u0569\u0003\u0103x\u0000\u0569\u056a\u0001\u0000\u0000\u0000\u056a"+ - "\u056b\u0006\u0096\u001e\u0000\u056b\u0140\u0001\u0000\u0000\u0000\u056c"+ - "\u056d\u0003\u00c7Z\u0000\u056d\u056e\u0001\u0000\u0000\u0000\u056e\u056f"+ - "\u0006\u0097#\u0000\u056f\u0142\u0001\u0000\u0000\u0000\u0570\u0571\u0003"+ - "\u0093@\u0000\u0571\u0572\u0001\u0000\u0000\u0000\u0572\u0573\u0006\u0098"+ - "\u001c\u0000\u0573\u0144\u0001\u0000\u0000\u0000\u0574\u0575\u0003\u00bd"+ - "U\u0000\u0575\u0576\u0001\u0000\u0000\u0000\u0576\u0577\u0006\u0099\u001d"+ - "\u0000\u0577\u0146\u0001\u0000\u0000\u0000\u0578\u0579\u0003I\u001b\u0000"+ - "\u0579\u057a\u0001\u0000\u0000\u0000\u057a\u057b\u0006\u009a\r\u0000\u057b"+ - "\u0148\u0001\u0000\u0000\u0000\u057c\u057d\u0003K\u001c\u0000\u057d\u057e"+ - "\u0001\u0000\u0000\u0000\u057e\u057f\u0006\u009b\r\u0000\u057f\u014a\u0001"+ - "\u0000\u0000\u0000\u0580\u0581\u0003M\u001d\u0000\u0581\u0582\u0001\u0000"+ - "\u0000\u0000\u0582\u0583\u0006\u009c\r\u0000\u0583\u014c\u0001\u0000\u0000"+ - "\u0000\u0584\u0585\u0003O\u001e\u0000\u0585\u0586\u0001\u0000\u0000\u0000"+ - "\u0586\u0587\u0006\u009d\u0014\u0000\u0587\u0588\u0006\u009d\u000e\u0000"+ - "\u0588\u014e\u0001\u0000\u0000\u0000\u0589\u058a\u0003{4\u0000\u058a\u058b"+ - "\u0001\u0000\u0000\u0000\u058b\u058c\u0006\u009e\u001b\u0000\u058c\u0150"+ - "\u0001\u0000\u0000\u0000\u058d\u058e\u0003\u0093@\u0000\u058e\u058f\u0001"+ - "\u0000\u0000\u0000\u058f\u0590\u0006\u009f\u001c\u0000\u0590\u0152\u0001"+ - "\u0000\u0000\u0000\u0591\u0592\u0003\u00bdU\u0000\u0592\u0593\u0001\u0000"+ - "\u0000\u0000\u0593\u0594\u0006\u00a0\u001d\u0000\u0594\u0154\u0001\u0000"+ - "\u0000\u0000\u0595\u0596\u0003\u00c7Z\u0000\u0596\u0597\u0001\u0000\u0000"+ - "\u0000\u0597\u0598\u0006\u00a1#\u0000\u0598\u0156\u0001\u0000\u0000\u0000"+ - "\u0599\u059a\u0003\u00c3X\u0000\u059a\u059b\u0001\u0000\u0000\u0000\u059b"+ - "\u059c\u0006\u00a2$\u0000\u059c\u0158\u0001\u0000\u0000\u0000\u059d\u059e"+ - "\u0003I\u001b\u0000\u059e\u059f\u0001\u0000\u0000\u0000\u059f\u05a0\u0006"+ - "\u00a3\r\u0000\u05a0\u015a\u0001\u0000\u0000\u0000\u05a1\u05a2\u0003K"+ - "\u001c\u0000\u05a2\u05a3\u0001\u0000\u0000\u0000\u05a3\u05a4\u0006\u00a4"+ - "\r\u0000\u05a4\u015c\u0001\u0000\u0000\u0000\u05a5\u05a6\u0003M\u001d"+ - "\u0000\u05a6\u05a7\u0001\u0000\u0000\u0000\u05a7\u05a8\u0006\u00a5\r\u0000"+ - "\u05a8\u015e\u0001\u0000\u0000\u0000\u05a9\u05aa\u0003O\u001e\u0000\u05aa"+ - "\u05ab\u0001\u0000\u0000\u0000\u05ab\u05ac\u0006\u00a6\u0014\u0000\u05ac"+ - "\u05ad\u0006\u00a6\u000e\u0000\u05ad\u0160\u0001\u0000\u0000\u0000\u05ae"+ - "\u05af\u0007\u0001\u0000\u0000\u05af\u05b0\u0007\t\u0000\u0000\u05b0\u05b1"+ - "\u0007\u000f\u0000\u0000\u05b1\u05b2\u0007\u0007\u0000\u0000\u05b2\u0162"+ - "\u0001\u0000\u0000\u0000\u05b3\u05b4\u0003I\u001b\u0000\u05b4\u05b5\u0001"+ - "\u0000\u0000\u0000\u05b5\u05b6\u0006\u00a8\r\u0000\u05b6\u0164\u0001\u0000"+ - "\u0000\u0000\u05b7\u05b8\u0003K\u001c\u0000\u05b8\u05b9\u0001\u0000\u0000"+ - "\u0000\u05b9\u05ba\u0006\u00a9\r\u0000\u05ba\u0166\u0001\u0000\u0000\u0000"+ - "\u05bb\u05bc\u0003M\u001d\u0000\u05bc\u05bd\u0001\u0000\u0000\u0000\u05bd"+ - "\u05be\u0006\u00aa\r\u0000\u05be\u0168\u0001\u0000\u0000\u0000\u05bf\u05c0"+ - "\u0003\u00c1W\u0000\u05c0\u05c1\u0001\u0000\u0000\u0000\u05c1\u05c2\u0006"+ - "\u00ab\u0015\u0000\u05c2\u05c3\u0006\u00ab\u000e\u0000\u05c3\u016a\u0001"+ - "\u0000\u0000\u0000\u05c4\u05c5\u0003u1\u0000\u05c5\u05c6\u0001\u0000\u0000"+ - "\u0000\u05c6\u05c7\u0006\u00ac\u0016\u0000\u05c7\u016c\u0001\u0000\u0000"+ - "\u0000\u05c8\u05ce\u0003[$\u0000\u05c9\u05ce\u0003Q\u001f\u0000\u05ca"+ - "\u05ce\u0003{4\u0000\u05cb\u05ce\u0003S \u0000\u05cc\u05ce\u0003a\'\u0000"+ - "\u05cd\u05c8\u0001\u0000\u0000\u0000\u05cd\u05c9\u0001\u0000\u0000\u0000"+ - "\u05cd\u05ca\u0001\u0000\u0000\u0000\u05cd\u05cb\u0001\u0000\u0000\u0000"+ - "\u05cd\u05cc\u0001\u0000\u0000\u0000\u05ce\u05cf\u0001\u0000\u0000\u0000"+ - "\u05cf\u05cd\u0001\u0000\u0000\u0000\u05cf\u05d0\u0001\u0000\u0000\u0000"+ - "\u05d0\u016e\u0001\u0000\u0000\u0000\u05d1\u05d2\u0003I\u001b\u0000\u05d2"+ - "\u05d3\u0001\u0000\u0000\u0000\u05d3\u05d4\u0006\u00ae\r\u0000\u05d4\u0170"+ - "\u0001\u0000\u0000\u0000\u05d5\u05d6\u0003K\u001c\u0000\u05d6\u05d7\u0001"+ - "\u0000\u0000\u0000\u05d7\u05d8\u0006\u00af\r\u0000\u05d8\u0172\u0001\u0000"+ - "\u0000\u0000\u05d9\u05da\u0003M\u001d\u0000\u05da\u05db\u0001\u0000\u0000"+ - "\u0000\u05db\u05dc\u0006\u00b0\r\u0000\u05dc\u0174\u0001\u0000\u0000\u0000"+ - "\u05dd\u05de\u0003O\u001e\u0000\u05de\u05df\u0001\u0000\u0000\u0000\u05df"+ - "\u05e0\u0006\u00b1\u0014\u0000\u05e0\u05e1\u0006\u00b1\u000e\u0000\u05e1"+ - "\u0176\u0001\u0000\u0000\u0000\u05e2\u05e3\u0003u1\u0000\u05e3\u05e4\u0001"+ - "\u0000\u0000\u0000\u05e4\u05e5\u0006\u00b2\u0016\u0000\u05e5\u0178\u0001"+ - "\u0000\u0000\u0000\u05e6\u05e7\u0003w2\u0000\u05e7\u05e8\u0001\u0000\u0000"+ - "\u0000\u05e8\u05e9\u0006\u00b3\u0017\u0000\u05e9\u017a\u0001\u0000\u0000"+ - "\u0000\u05ea\u05eb\u0003{4\u0000\u05eb\u05ec\u0001\u0000\u0000\u0000\u05ec"+ - "\u05ed\u0006\u00b4\u001b\u0000\u05ed\u017c\u0001\u0000\u0000\u0000\u05ee"+ - "\u05ef\u0003\u0125\u0089\u0000\u05ef\u05f0\u0001\u0000\u0000\u0000\u05f0"+ - "\u05f1\u0006\u00b5%\u0000\u05f1\u05f2\u0006\u00b5&\u0000\u05f2\u017e\u0001"+ - "\u0000\u0000\u0000\u05f3\u05f4\u0003\u00e9k\u0000\u05f4\u05f5\u0001\u0000"+ - "\u0000\u0000\u05f5\u05f6\u0006\u00b6\u0019\u0000\u05f6\u0180\u0001\u0000"+ - "\u0000\u0000\u05f7\u05f8\u0003e)\u0000\u05f8\u05f9\u0001\u0000\u0000\u0000"+ - "\u05f9\u05fa\u0006\u00b7\u001a\u0000\u05fa\u0182\u0001\u0000\u0000\u0000"+ - "\u05fb\u05fc\u0003I\u001b\u0000\u05fc\u05fd\u0001\u0000\u0000\u0000\u05fd"+ - "\u05fe\u0006\u00b8\r\u0000\u05fe\u0184\u0001\u0000\u0000\u0000\u05ff\u0600"+ - "\u0003K\u001c\u0000\u0600\u0601\u0001\u0000\u0000\u0000\u0601\u0602\u0006"+ - "\u00b9\r\u0000\u0602\u0186\u0001\u0000\u0000\u0000\u0603\u0604\u0003M"+ - "\u001d\u0000\u0604\u0605\u0001\u0000\u0000\u0000\u0605\u0606\u0006\u00ba"+ - "\r\u0000\u0606\u0188\u0001\u0000\u0000\u0000\u0607\u0608\u0003O\u001e"+ - "\u0000\u0608\u0609\u0001\u0000\u0000\u0000\u0609\u060a\u0006\u00bb\u0014"+ - "\u0000\u060a\u060b\u0006\u00bb\u000e\u0000\u060b\u060c\u0006\u00bb\u000e"+ - "\u0000\u060c\u018a\u0001\u0000\u0000\u0000\u060d\u060e\u0003w2\u0000\u060e"+ - "\u060f\u0001\u0000\u0000\u0000\u060f\u0610\u0006\u00bc\u0017\u0000\u0610"+ - "\u018c\u0001\u0000\u0000\u0000\u0611\u0612\u0003{4\u0000\u0612\u0613\u0001"+ - "\u0000\u0000\u0000\u0613\u0614\u0006\u00bd\u001b\u0000\u0614\u018e\u0001"+ - "\u0000\u0000\u0000\u0615\u0616\u0003\u0103x\u0000\u0616\u0617\u0001\u0000"+ - "\u0000\u0000\u0617\u0618\u0006\u00be\u001e\u0000\u0618\u0190\u0001\u0000"+ - "\u0000\u0000\u0619\u061a\u0003I\u001b\u0000\u061a\u061b\u0001\u0000\u0000"+ - "\u0000\u061b\u061c\u0006\u00bf\r\u0000\u061c\u0192\u0001\u0000\u0000\u0000"+ - "\u061d\u061e\u0003K\u001c\u0000\u061e\u061f\u0001\u0000\u0000\u0000\u061f"+ - "\u0620\u0006\u00c0\r\u0000\u0620\u0194\u0001\u0000\u0000\u0000\u0621\u0622"+ - "\u0003M\u001d\u0000\u0622\u0623\u0001\u0000\u0000\u0000\u0623\u0624\u0006"+ - "\u00c1\r\u0000\u0624\u0196\u0001\u0000\u0000\u0000\u0625\u0626\u0003O"+ - "\u001e\u0000\u0626\u0627\u0001\u0000\u0000\u0000\u0627\u0628\u0006\u00c2"+ - "\u0014\u0000\u0628\u0629\u0006\u00c2\u000e\u0000\u0629\u0198\u0001\u0000"+ - "\u0000\u0000\u062a\u062b\u0007#\u0000\u0000\u062b\u062c\u0007\u0007\u0000"+ - "\u0000\u062c\u062d\u0007\u0001\u0000\u0000\u062d\u062e\u0007\t\u0000\u0000"+ - "\u062e\u019a\u0001\u0000\u0000\u0000\u062f\u0630\u0003\u0117\u0082\u0000"+ - "\u0630\u0631\u0001\u0000\u0000\u0000\u0631\u0632\u0006\u00c4\'\u0000\u0632"+ - "\u019c\u0001\u0000\u0000\u0000\u0633\u0634\u0003\u0125\u0089\u0000\u0634"+ - "\u0635\u0001\u0000\u0000\u0000\u0635\u0636\u0006\u00c5%\u0000\u0636\u0637"+ - "\u0006\u00c5\u000e\u0000\u0637\u0638\u0006\u00c5\u0000\u0000\u0638\u019e"+ - "\u0001\u0000\u0000\u0000\u0639\u063a\u0007\u0014\u0000\u0000\u063a\u063b"+ - "\u0007\u0002\u0000\u0000\u063b\u063c\u0007\u0001\u0000\u0000\u063c\u063d"+ - "\u0007\t\u0000\u0000\u063d\u063e\u0007\u0011\u0000\u0000\u063e\u063f\u0001"+ - "\u0000\u0000\u0000\u063f\u0640\u0006\u00c6\u000e\u0000\u0640\u0641\u0006"+ - "\u00c6\u0000\u0000\u0641\u01a0\u0001\u0000\u0000\u0000\u0642\u0643\u0003"+ - "\u00e9k\u0000\u0643\u0644\u0001\u0000\u0000\u0000\u0644\u0645\u0006\u00c7"+ - "\u0019\u0000\u0645\u01a2\u0001\u0000\u0000\u0000\u0646\u0647\u0003e)\u0000"+ - "\u0647\u0648\u0001\u0000\u0000\u0000\u0648\u0649\u0006\u00c8\u001a\u0000"+ - "\u0649\u01a4\u0001\u0000\u0000\u0000\u064a\u064b\u0003u1\u0000\u064b\u064c"+ - "\u0001\u0000\u0000\u0000\u064c\u064d\u0006\u00c9\u0016\u0000\u064d\u01a6"+ - "\u0001\u0000\u0000\u0000\u064e\u064f\u0003\u00c3X\u0000\u064f\u0650\u0001"+ - "\u0000\u0000\u0000\u0650\u0651\u0006\u00ca$\u0000\u0651\u01a8\u0001\u0000"+ - "\u0000\u0000\u0652\u0653\u0003\u00c7Z\u0000\u0653\u0654\u0001\u0000\u0000"+ - "\u0000\u0654\u0655\u0006\u00cb#\u0000\u0655\u01aa\u0001\u0000\u0000\u0000"+ - "\u0656\u0657\u0003I\u001b\u0000\u0657\u0658\u0001\u0000\u0000\u0000\u0658"+ - "\u0659\u0006\u00cc\r\u0000\u0659\u01ac\u0001\u0000\u0000\u0000\u065a\u065b"+ - "\u0003K\u001c\u0000\u065b\u065c\u0001\u0000\u0000\u0000\u065c\u065d\u0006"+ - "\u00cd\r\u0000\u065d\u01ae\u0001\u0000\u0000\u0000\u065e\u065f\u0003M"+ - "\u001d\u0000\u065f\u0660\u0001\u0000\u0000\u0000\u0660\u0661\u0006\u00ce"+ - "\r\u0000\u0661\u01b0\u0001\u0000\u0000\u0000\u0662\u0663\u0003O\u001e"+ - "\u0000\u0663\u0664\u0001\u0000\u0000\u0000\u0664\u0665\u0006\u00cf\u0014"+ - "\u0000\u0665\u0666\u0006\u00cf\u000e\u0000\u0666\u01b2\u0001\u0000\u0000"+ - "\u0000\u0667\u0668\u0003\u00e9k\u0000\u0668\u0669\u0001\u0000\u0000\u0000"+ - "\u0669\u066a\u0006\u00d0\u0019\u0000\u066a\u066b\u0006\u00d0\u000e\u0000"+ - "\u066b\u066c\u0006\u00d0(\u0000\u066c\u01b4\u0001\u0000\u0000\u0000\u066d"+ - "\u066e\u0003e)\u0000\u066e\u066f\u0001\u0000\u0000\u0000\u066f\u0670\u0006"+ - "\u00d1\u001a\u0000\u0670\u0671\u0006\u00d1\u000e\u0000\u0671\u0672\u0006"+ - "\u00d1(\u0000\u0672\u01b6\u0001\u0000\u0000\u0000\u0673\u0674\u0003I\u001b"+ - "\u0000\u0674\u0675\u0001\u0000\u0000\u0000\u0675\u0676\u0006\u00d2\r\u0000"+ - "\u0676\u01b8\u0001\u0000\u0000\u0000\u0677\u0678\u0003K\u001c\u0000\u0678"+ - "\u0679\u0001\u0000\u0000\u0000\u0679\u067a\u0006\u00d3\r\u0000\u067a\u01ba"+ - "\u0001\u0000\u0000\u0000\u067b\u067c\u0003M\u001d\u0000\u067c\u067d\u0001"+ - "\u0000\u0000\u0000\u067d\u067e\u0006\u00d4\r\u0000\u067e\u01bc\u0001\u0000"+ - "\u0000\u0000\u067f\u0680\u0003u1\u0000\u0680\u0681\u0001\u0000\u0000\u0000"+ - "\u0681\u0682\u0006\u00d5\u0016\u0000\u0682\u0683\u0006\u00d5\u000e\u0000"+ - "\u0683\u0684\u0006\u00d5\u000b\u0000\u0684\u01be\u0001\u0000\u0000\u0000"+ - "\u0685\u0686\u0003w2\u0000\u0686\u0687\u0001\u0000\u0000\u0000\u0687\u0688"+ - "\u0006\u00d6\u0017\u0000\u0688\u0689\u0006\u00d6\u000e\u0000\u0689\u068a"+ - "\u0006\u00d6\u000b\u0000\u068a\u01c0\u0001\u0000\u0000\u0000\u068b\u068c"+ - "\u0003I\u001b\u0000\u068c\u068d\u0001\u0000\u0000\u0000\u068d\u068e\u0006"+ - "\u00d7\r\u0000\u068e\u01c2\u0001\u0000\u0000\u0000\u068f\u0690\u0003K"+ - "\u001c\u0000\u0690\u0691\u0001\u0000\u0000\u0000\u0691\u0692\u0006\u00d8"+ - "\r\u0000\u0692\u01c4\u0001\u0000\u0000\u0000\u0693\u0694\u0003M\u001d"+ - "\u0000\u0694\u0695\u0001\u0000\u0000\u0000\u0695\u0696\u0006\u00d9\r\u0000"+ - "\u0696\u01c6\u0001\u0000\u0000\u0000\u0697\u0698\u0003\u00c7Z\u0000\u0698"+ - "\u0699\u0001\u0000\u0000\u0000\u0699\u069a\u0006\u00da\u000e\u0000\u069a"+ - "\u069b\u0006\u00da\u0000\u0000\u069b\u069c\u0006\u00da#\u0000\u069c\u01c8"+ - "\u0001\u0000\u0000\u0000\u069d\u069e\u0003\u00c3X\u0000\u069e\u069f\u0001"+ - "\u0000\u0000\u0000\u069f\u06a0\u0006\u00db\u000e\u0000\u06a0\u06a1\u0006"+ - "\u00db\u0000\u0000\u06a1\u06a2\u0006\u00db$\u0000\u06a2\u01ca\u0001\u0000"+ - "\u0000\u0000\u06a3\u06a4\u0003k,\u0000\u06a4\u06a5\u0001\u0000\u0000\u0000"+ - "\u06a5\u06a6\u0006\u00dc\u000e\u0000\u06a6\u06a7\u0006\u00dc\u0000\u0000"+ - "\u06a7\u06a8\u0006\u00dc)\u0000\u06a8\u01cc\u0001\u0000\u0000\u0000\u06a9"+ - "\u06aa\u0003O\u001e\u0000\u06aa\u06ab\u0001\u0000\u0000\u0000\u06ab\u06ac"+ - "\u0006\u00dd\u0014\u0000\u06ac\u06ad\u0006\u00dd\u000e\u0000\u06ad\u01ce"+ - "\u0001\u0000\u0000\u0000\u06ae\u06af\u0003O\u001e\u0000\u06af\u06b0\u0001"+ - "\u0000\u0000\u0000\u06b0\u06b1\u0006\u00de\u0014\u0000\u06b1\u06b2\u0006"+ - "\u00de\u000e\u0000\u06b2\u01d0\u0001\u0000\u0000\u0000\u06b3\u06b4\u0003"+ - "\u0125\u0089\u0000\u06b4\u06b5\u0001\u0000\u0000\u0000\u06b5\u06b6\u0006"+ - "\u00df%\u0000\u06b6\u01d2\u0001\u0000\u0000\u0000\u06b7\u06b8\u0003\u0117"+ - "\u0082\u0000\u06b8\u06b9\u0001\u0000\u0000\u0000\u06b9\u06ba\u0006\u00e0"+ - "\'\u0000\u06ba\u01d4\u0001\u0000\u0000\u0000\u06bb\u06bc\u0003{4\u0000"+ - "\u06bc\u06bd\u0001\u0000\u0000\u0000\u06bd\u06be\u0006\u00e1\u001b\u0000"+ - "\u06be\u01d6\u0001\u0000\u0000\u0000\u06bf\u06c0\u0003w2\u0000\u06c0\u06c1"+ - "\u0001\u0000\u0000\u0000\u06c1\u06c2\u0006\u00e2\u0017\u0000\u06c2\u01d8"+ - "\u0001\u0000\u0000\u0000\u06c3\u06c4\u0003\u00c7Z\u0000\u06c4\u06c5\u0001"+ - "\u0000\u0000\u0000\u06c5\u06c6\u0006\u00e3#\u0000\u06c6\u01da\u0001\u0000"+ - "\u0000\u0000\u06c7\u06c8\u0003\u00c3X\u0000\u06c8\u06c9\u0001\u0000\u0000"+ - "\u0000\u06c9\u06ca\u0006\u00e4$\u0000\u06ca\u01dc\u0001\u0000\u0000\u0000"+ - "\u06cb\u06cc\u0003I\u001b\u0000\u06cc\u06cd\u0001\u0000\u0000\u0000\u06cd"+ - "\u06ce\u0006\u00e5\r\u0000\u06ce\u01de\u0001\u0000\u0000\u0000\u06cf\u06d0"+ - "\u0003K\u001c\u0000\u06d0\u06d1\u0001\u0000\u0000\u0000\u06d1\u06d2\u0006"+ - "\u00e6\r\u0000\u06d2\u01e0\u0001\u0000\u0000\u0000\u06d3\u06d4\u0003M"+ - "\u001d\u0000\u06d4\u06d5\u0001\u0000\u0000\u0000\u06d5\u06d6\u0006\u00e7"+ - "\r\u0000\u06d6\u01e2\u0001\u0000\u0000\u0000\u06d7\u06d8\u0003O\u001e"+ - "\u0000\u06d8\u06d9\u0001\u0000\u0000\u0000\u06d9\u06da\u0006\u00e8\u0014"+ - "\u0000\u06da\u06db\u0006\u00e8\u000e\u0000\u06db\u01e4\u0001\u0000\u0000"+ - "\u0000\u06dc\u06dd\u0003\u00c3X\u0000\u06dd\u06de\u0001\u0000\u0000\u0000"+ - "\u06de\u06df\u0006\u00e9$\u0000\u06df\u01e6\u0001\u0000\u0000\u0000\u06e0"+ - "\u06e1\u0003M\u001d\u0000\u06e1\u06e2\u0001\u0000\u0000\u0000\u06e2\u06e3"+ - "\u0006\u00ea\r\u0000\u06e3\u01e8\u0001\u0000\u0000\u0000\u06e4\u06e5\u0003"+ - "I\u001b\u0000\u06e5\u06e6\u0001\u0000\u0000\u0000\u06e6\u06e7\u0006\u00eb"+ - "\r\u0000\u06e7\u01ea\u0001\u0000\u0000\u0000\u06e8\u06e9\u0003K\u001c"+ - "\u0000\u06e9\u06ea\u0001\u0000\u0000\u0000\u06ea\u06eb\u0006\u00ec\r\u0000"+ - "\u06eb\u01ec\u0001\u0000\u0000\u0000\u06ec\u06ed\u0003\u0089;\u0000\u06ed"+ - "\u06ee\u0001\u0000\u0000\u0000\u06ee\u06ef\u0006\u00ed*\u0000\u06ef\u06f0"+ - "\u0006\u00ed\u0013\u0000\u06f0\u01ee\u0001\u0000\u0000\u0000\u06f1\u06f2"+ - "\u0003\u0097B\u0000\u06f2\u06f3\u0001\u0000\u0000\u0000\u06f3\u06f4\u0006"+ - "\u00ee+\u0000\u06f4\u06f5\u0006\u00ee\u000e\u0000\u06f5\u01f0\u0001\u0000"+ - "\u0000\u0000\u06f6\u06f7\u0003O\u001e\u0000\u06f7\u06f8\u0001\u0000\u0000"+ - "\u0000\u06f8\u06f9\u0006\u00ef\u0014\u0000\u06f9\u06fa\u0006\u00ef\u000e"+ - "\u0000\u06fa\u01f2\u0001\u0000\u0000\u0000\u06fb\u06fc\u0003M\u001d\u0000"+ - "\u06fc\u06fd\u0001\u0000\u0000\u0000\u06fd\u06fe\u0006\u00f0\r\u0000\u06fe"+ - "\u01f4\u0001\u0000\u0000\u0000\u06ff\u0700\u0003I\u001b\u0000\u0700\u0701"+ - "\u0001\u0000\u0000\u0000\u0701\u0702\u0006\u00f1\r\u0000\u0702\u01f6\u0001"+ - "\u0000\u0000\u0000\u0703\u0704\u0003K\u001c\u0000\u0704\u0705\u0001\u0000"+ - "\u0000\u0000\u0705\u0706\u0006\u00f2\r\u0000\u0706\u01f8\u0001\u0000\u0000"+ - "\u0000E\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f"+ - "\r\u000e\u000f\u0010\u0011\u0012\u02e9\u02f3\u02f7\u02fa\u0303\u0305\u0310"+ - "\u0323\u0328\u0331\u0338\u033d\u033f\u034a\u0352\u0355\u0357\u035c\u0361"+ - "\u0367\u036e\u0373\u0379\u037c\u0384\u0388\u0416\u041b\u0422\u0424\u0434"+ - "\u0439\u043e\u0440\u0446\u0493\u0498\u04c7\u04cb\u04d0\u04d5\u04da\u04dc"+ - "\u04e0\u04e2\u0537\u053b\u0540\u05cd\u05cf,\u0005\u0001\u0000\u0005\u0004"+ - "\u0000\u0005\u0006\u0000\u0005\u0002\u0000\u0005\u0003\u0000\u0005\b\u0000"+ - "\u0005\u0005\u0000\u0005\t\u0000\u0005\r\u0000\u0005\u0010\u0000\u0005"+ - "\u000b\u0000\u0005\u000e\u0000\u0005\u0012\u0000\u0000\u0001\u0000\u0004"+ - "\u0000\u0000\u0007\u0010\u0000\u0007\u000e\u0000\u0007\t\u0000\u0007J"+ - "\u0000\u0005\u0000\u0000\u0007\u001f\u0000\u0007K\u0000\u0007(\u0000\u0007"+ - ")\u0000\u0007&\u0000\u0007U\u0000\u0007 \u0000\u0007+\u0000\u00077\u0000"+ - "\u0007I\u0000\u0007Y\u0000\u0005\n\u0000\u0005\u0007\u0000\u0007c\u0000"+ - "\u0007b\u0000\u0007M\u0000\u0007L\u0000\u0007a\u0000\u0005\f\u0000\u0007"+ - "]\u0000\u0005\u000f\u0000\u0007#\u0000\u00072\u0000\u00079\u0000"; + "\r\u01ab\u0001\u0000\u0000\u0000\u000e\u01ad\u0001\u0000\u0000\u0000\u000e"+ + "\u01af\u0001\u0000\u0000\u0000\u000e\u01b1\u0001\u0000\u0000\u0000\u000e"+ + "\u01b3\u0001\u0000\u0000\u0000\u000e\u01b5\u0001\u0000\u0000\u0000\u000e"+ + "\u01b7\u0001\u0000\u0000\u0000\u000f\u01b9\u0001\u0000\u0000\u0000\u000f"+ + "\u01bb\u0001\u0000\u0000\u0000\u000f\u01bd\u0001\u0000\u0000\u0000\u000f"+ + "\u01bf\u0001\u0000\u0000\u0000\u000f\u01c1\u0001\u0000\u0000\u0000\u000f"+ + "\u01c3\u0001\u0000\u0000\u0000\u000f\u01c5\u0001\u0000\u0000\u0000\u000f"+ + "\u01c7\u0001\u0000\u0000\u0000\u000f\u01c9\u0001\u0000\u0000\u0000\u0010"+ + "\u01cb\u0001\u0000\u0000\u0000\u0010\u01cd\u0001\u0000\u0000\u0000\u0010"+ + "\u01cf\u0001\u0000\u0000\u0000\u0010\u01d1\u0001\u0000\u0000\u0000\u0010"+ + "\u01d3\u0001\u0000\u0000\u0000\u0010\u01d5\u0001\u0000\u0000\u0000\u0010"+ + "\u01d7\u0001\u0000\u0000\u0000\u0010\u01d9\u0001\u0000\u0000\u0000\u0010"+ + "\u01db\u0001\u0000\u0000\u0000\u0010\u01dd\u0001\u0000\u0000\u0000\u0011"+ + "\u01df\u0001\u0000\u0000\u0000\u0011\u01e1\u0001\u0000\u0000\u0000\u0011"+ + "\u01e3\u0001\u0000\u0000\u0000\u0011\u01e5\u0001\u0000\u0000\u0000\u0011"+ + "\u01e7\u0001\u0000\u0000\u0000\u0012\u01e9\u0001\u0000\u0000\u0000\u0012"+ + "\u01eb\u0001\u0000\u0000\u0000\u0012\u01ed\u0001\u0000\u0000\u0000\u0012"+ + "\u01ef\u0001\u0000\u0000\u0000\u0012\u01f1\u0001\u0000\u0000\u0000\u0013"+ + "\u01f3\u0001\u0000\u0000\u0000\u0015\u01fd\u0001\u0000\u0000\u0000\u0017"+ + "\u0204\u0001\u0000\u0000\u0000\u0019\u020d\u0001\u0000\u0000\u0000\u001b"+ + "\u0214\u0001\u0000\u0000\u0000\u001d\u021e\u0001\u0000\u0000\u0000\u001f"+ + "\u0225\u0001\u0000\u0000\u0000!\u022c\u0001\u0000\u0000\u0000#\u0233\u0001"+ + "\u0000\u0000\u0000%\u023b\u0001\u0000\u0000\u0000\'\u0247\u0001\u0000"+ + "\u0000\u0000)\u0250\u0001\u0000\u0000\u0000+\u0256\u0001\u0000\u0000\u0000"+ + "-\u025d\u0001\u0000\u0000\u0000/\u0264\u0001\u0000\u0000\u00001\u026c"+ + "\u0001\u0000\u0000\u00003\u0274\u0001\u0000\u0000\u00005\u027d\u0001\u0000"+ + "\u0000\u00007\u028d\u0001\u0000\u0000\u00009\u029c\u0001\u0000\u0000\u0000"+ + ";\u02a8\u0001\u0000\u0000\u0000=\u02b4\u0001\u0000\u0000\u0000?\u02bf"+ + "\u0001\u0000\u0000\u0000A\u02c7\u0001\u0000\u0000\u0000C\u02cf\u0001\u0000"+ + "\u0000\u0000E\u02d8\u0001\u0000\u0000\u0000G\u02e1\u0001\u0000\u0000\u0000"+ + "I\u02e7\u0001\u0000\u0000\u0000K\u02f8\u0001\u0000\u0000\u0000M\u0308"+ + "\u0001\u0000\u0000\u0000O\u030e\u0001\u0000\u0000\u0000Q\u0312\u0001\u0000"+ + "\u0000\u0000S\u0314\u0001\u0000\u0000\u0000U\u0316\u0001\u0000\u0000\u0000"+ + "W\u0319\u0001\u0000\u0000\u0000Y\u031b\u0001\u0000\u0000\u0000[\u0324"+ + "\u0001\u0000\u0000\u0000]\u0326\u0001\u0000\u0000\u0000_\u032b\u0001\u0000"+ + "\u0000\u0000a\u032d\u0001\u0000\u0000\u0000c\u0332\u0001\u0000\u0000\u0000"+ + "e\u0351\u0001\u0000\u0000\u0000g\u0354\u0001\u0000\u0000\u0000i\u0382"+ + "\u0001\u0000\u0000\u0000k\u0384\u0001\u0000\u0000\u0000m\u0387\u0001\u0000"+ + "\u0000\u0000o\u038b\u0001\u0000\u0000\u0000q\u038f\u0001\u0000\u0000\u0000"+ + "s\u0391\u0001\u0000\u0000\u0000u\u0394\u0001\u0000\u0000\u0000w\u0396"+ + "\u0001\u0000\u0000\u0000y\u0398\u0001\u0000\u0000\u0000{\u039d\u0001\u0000"+ + "\u0000\u0000}\u039f\u0001\u0000\u0000\u0000\u007f\u03a5\u0001\u0000\u0000"+ + "\u0000\u0081\u03ab\u0001\u0000\u0000\u0000\u0083\u03ae\u0001\u0000\u0000"+ + "\u0000\u0085\u03b1\u0001\u0000\u0000\u0000\u0087\u03b6\u0001\u0000\u0000"+ + "\u0000\u0089\u03bb\u0001\u0000\u0000\u0000\u008b\u03bf\u0001\u0000\u0000"+ + "\u0000\u008d\u03c4\u0001\u0000\u0000\u0000\u008f\u03ca\u0001\u0000\u0000"+ + "\u0000\u0091\u03cd\u0001\u0000\u0000\u0000\u0093\u03cf\u0001\u0000\u0000"+ + "\u0000\u0095\u03d5\u0001\u0000\u0000\u0000\u0097\u03da\u0001\u0000\u0000"+ + "\u0000\u0099\u03dd\u0001\u0000\u0000\u0000\u009b\u03e0\u0001\u0000\u0000"+ + "\u0000\u009d\u03e3\u0001\u0000\u0000\u0000\u009f\u03e5\u0001\u0000\u0000"+ + "\u0000\u00a1\u03e8\u0001\u0000\u0000\u0000\u00a3\u03ea\u0001\u0000\u0000"+ + "\u0000\u00a5\u03ed\u0001\u0000\u0000\u0000\u00a7\u03ef\u0001\u0000\u0000"+ + "\u0000\u00a9\u03f1\u0001\u0000\u0000\u0000\u00ab\u03f3\u0001\u0000\u0000"+ + "\u0000\u00ad\u03f5\u0001\u0000\u0000\u0000\u00af\u03f7\u0001\u0000\u0000"+ + "\u0000\u00b1\u03f9\u0001\u0000\u0000\u0000\u00b3\u03fb\u0001\u0000\u0000"+ + "\u0000\u00b5\u0410\u0001\u0000\u0000\u0000\u00b7\u0412\u0001\u0000\u0000"+ + "\u0000\u00b9\u0417\u0001\u0000\u0000\u0000\u00bb\u041c\u0001\u0000\u0000"+ + "\u0000\u00bd\u0421\u0001\u0000\u0000\u0000\u00bf\u0436\u0001\u0000\u0000"+ + "\u0000\u00c1\u0438\u0001\u0000\u0000\u0000\u00c3\u0440\u0001\u0000\u0000"+ + "\u0000\u00c5\u0442\u0001\u0000\u0000\u0000\u00c7\u0446\u0001\u0000\u0000"+ + "\u0000\u00c9\u044a\u0001\u0000\u0000\u0000\u00cb\u044e\u0001\u0000\u0000"+ + "\u0000\u00cd\u0453\u0001\u0000\u0000\u0000\u00cf\u0458\u0001\u0000\u0000"+ + "\u0000\u00d1\u045c\u0001\u0000\u0000\u0000\u00d3\u0460\u0001\u0000\u0000"+ + "\u0000\u00d5\u0464\u0001\u0000\u0000\u0000\u00d7\u0469\u0001\u0000\u0000"+ + "\u0000\u00d9\u046d\u0001\u0000\u0000\u0000\u00db\u0471\u0001\u0000\u0000"+ + "\u0000\u00dd\u0475\u0001\u0000\u0000\u0000\u00df\u0479\u0001\u0000\u0000"+ + "\u0000\u00e1\u047d\u0001\u0000\u0000\u0000\u00e3\u0489\u0001\u0000\u0000"+ + "\u0000\u00e5\u048c\u0001\u0000\u0000\u0000\u00e7\u0490\u0001\u0000\u0000"+ + "\u0000\u00e9\u0494\u0001\u0000\u0000\u0000\u00eb\u0498\u0001\u0000\u0000"+ + "\u0000\u00ed\u049c\u0001\u0000\u0000\u0000\u00ef\u04a0\u0001\u0000\u0000"+ + "\u0000\u00f1\u04a4\u0001\u0000\u0000\u0000\u00f3\u04a9\u0001\u0000\u0000"+ + "\u0000\u00f5\u04ad\u0001\u0000\u0000\u0000\u00f7\u04b1\u0001\u0000\u0000"+ + "\u0000\u00f9\u04b5\u0001\u0000\u0000\u0000\u00fb\u04bd\u0001\u0000\u0000"+ + "\u0000\u00fd\u04d2\u0001\u0000\u0000\u0000\u00ff\u04d6\u0001\u0000\u0000"+ + "\u0000\u0101\u04da\u0001\u0000\u0000\u0000\u0103\u04de\u0001\u0000\u0000"+ + "\u0000\u0105\u04e2\u0001\u0000\u0000\u0000\u0107\u04e6\u0001\u0000\u0000"+ + "\u0000\u0109\u04eb\u0001\u0000\u0000\u0000\u010b\u04ef\u0001\u0000\u0000"+ + "\u0000\u010d\u04f3\u0001\u0000\u0000\u0000\u010f\u04f7\u0001\u0000\u0000"+ + "\u0000\u0111\u04fb\u0001\u0000\u0000\u0000\u0113\u04ff\u0001\u0000\u0000"+ + "\u0000\u0115\u0502\u0001\u0000\u0000\u0000\u0117\u0506\u0001\u0000\u0000"+ + "\u0000\u0119\u050a\u0001\u0000\u0000\u0000\u011b\u050e\u0001\u0000\u0000"+ + "\u0000\u011d\u0512\u0001\u0000\u0000\u0000\u011f\u0517\u0001\u0000\u0000"+ + "\u0000\u0121\u051c\u0001\u0000\u0000\u0000\u0123\u0521\u0001\u0000\u0000"+ + "\u0000\u0125\u0528\u0001\u0000\u0000\u0000\u0127\u0531\u0001\u0000\u0000"+ + "\u0000\u0129\u0538\u0001\u0000\u0000\u0000\u012b\u053c\u0001\u0000\u0000"+ + "\u0000\u012d\u0540\u0001\u0000\u0000\u0000\u012f\u0544\u0001\u0000\u0000"+ + "\u0000\u0131\u0548\u0001\u0000\u0000\u0000\u0133\u054e\u0001\u0000\u0000"+ + "\u0000\u0135\u0552\u0001\u0000\u0000\u0000\u0137\u0556\u0001\u0000\u0000"+ + "\u0000\u0139\u055a\u0001\u0000\u0000\u0000\u013b\u055e\u0001\u0000\u0000"+ + "\u0000\u013d\u0562\u0001\u0000\u0000\u0000\u013f\u0566\u0001\u0000\u0000"+ + "\u0000\u0141\u056a\u0001\u0000\u0000\u0000\u0143\u056e\u0001\u0000\u0000"+ + "\u0000\u0145\u0572\u0001\u0000\u0000\u0000\u0147\u0576\u0001\u0000\u0000"+ + "\u0000\u0149\u057a\u0001\u0000\u0000\u0000\u014b\u057f\u0001\u0000\u0000"+ + "\u0000\u014d\u0583\u0001\u0000\u0000\u0000\u014f\u0587\u0001\u0000\u0000"+ + "\u0000\u0151\u058b\u0001\u0000\u0000\u0000\u0153\u058f\u0001\u0000\u0000"+ + "\u0000\u0155\u0593\u0001\u0000\u0000\u0000\u0157\u0597\u0001\u0000\u0000"+ + "\u0000\u0159\u059b\u0001\u0000\u0000\u0000\u015b\u059f\u0001\u0000\u0000"+ + "\u0000\u015d\u05a4\u0001\u0000\u0000\u0000\u015f\u05a9\u0001\u0000\u0000"+ + "\u0000\u0161\u05ad\u0001\u0000\u0000\u0000\u0163\u05b1\u0001\u0000\u0000"+ + "\u0000\u0165\u05b5\u0001\u0000\u0000\u0000\u0167\u05ba\u0001\u0000\u0000"+ + "\u0000\u0169\u05c3\u0001\u0000\u0000\u0000\u016b\u05c7\u0001\u0000\u0000"+ + "\u0000\u016d\u05cb\u0001\u0000\u0000\u0000\u016f\u05cf\u0001\u0000\u0000"+ + "\u0000\u0171\u05d3\u0001\u0000\u0000\u0000\u0173\u05d8\u0001\u0000\u0000"+ + "\u0000\u0175\u05dc\u0001\u0000\u0000\u0000\u0177\u05e0\u0001\u0000\u0000"+ + "\u0000\u0179\u05e4\u0001\u0000\u0000\u0000\u017b\u05e9\u0001\u0000\u0000"+ + "\u0000\u017d\u05ed\u0001\u0000\u0000\u0000\u017f\u05f1\u0001\u0000\u0000"+ + "\u0000\u0181\u05f5\u0001\u0000\u0000\u0000\u0183\u05f9\u0001\u0000\u0000"+ + "\u0000\u0185\u05fd\u0001\u0000\u0000\u0000\u0187\u0603\u0001\u0000\u0000"+ + "\u0000\u0189\u0607\u0001\u0000\u0000\u0000\u018b\u060b\u0001\u0000\u0000"+ + "\u0000\u018d\u060f\u0001\u0000\u0000\u0000\u018f\u0613\u0001\u0000\u0000"+ + "\u0000\u0191\u0617\u0001\u0000\u0000\u0000\u0193\u061b\u0001\u0000\u0000"+ + "\u0000\u0195\u0620\u0001\u0000\u0000\u0000\u0197\u0625\u0001\u0000\u0000"+ + "\u0000\u0199\u0629\u0001\u0000\u0000\u0000\u019b\u062f\u0001\u0000\u0000"+ + "\u0000\u019d\u0638\u0001\u0000\u0000\u0000\u019f\u063c\u0001\u0000\u0000"+ + "\u0000\u01a1\u0640\u0001\u0000\u0000\u0000\u01a3\u0644\u0001\u0000\u0000"+ + "\u0000\u01a5\u0648\u0001\u0000\u0000\u0000\u01a7\u064c\u0001\u0000\u0000"+ + "\u0000\u01a9\u0650\u0001\u0000\u0000\u0000\u01ab\u0654\u0001\u0000\u0000"+ + "\u0000\u01ad\u0658\u0001\u0000\u0000\u0000\u01af\u065d\u0001\u0000\u0000"+ + "\u0000\u01b1\u0663\u0001\u0000\u0000\u0000\u01b3\u0669\u0001\u0000\u0000"+ + "\u0000\u01b5\u066d\u0001\u0000\u0000\u0000\u01b7\u0671\u0001\u0000\u0000"+ + "\u0000\u01b9\u0675\u0001\u0000\u0000\u0000\u01bb\u067b\u0001\u0000\u0000"+ + "\u0000\u01bd\u0681\u0001\u0000\u0000\u0000\u01bf\u0685\u0001\u0000\u0000"+ + "\u0000\u01c1\u0689\u0001\u0000\u0000\u0000\u01c3\u068d\u0001\u0000\u0000"+ + "\u0000\u01c5\u0693\u0001\u0000\u0000\u0000\u01c7\u0699\u0001\u0000\u0000"+ + "\u0000\u01c9\u069f\u0001\u0000\u0000\u0000\u01cb\u06a4\u0001\u0000\u0000"+ + "\u0000\u01cd\u06a9\u0001\u0000\u0000\u0000\u01cf\u06ad\u0001\u0000\u0000"+ + "\u0000\u01d1\u06b1\u0001\u0000\u0000\u0000\u01d3\u06b5\u0001\u0000\u0000"+ + "\u0000\u01d5\u06b9\u0001\u0000\u0000\u0000\u01d7\u06bd\u0001\u0000\u0000"+ + "\u0000\u01d9\u06c1\u0001\u0000\u0000\u0000\u01db\u06c5\u0001\u0000\u0000"+ + "\u0000\u01dd\u06c9\u0001\u0000\u0000\u0000\u01df\u06cd\u0001\u0000\u0000"+ + "\u0000\u01e1\u06d2\u0001\u0000\u0000\u0000\u01e3\u06d6\u0001\u0000\u0000"+ + "\u0000\u01e5\u06da\u0001\u0000\u0000\u0000\u01e7\u06de\u0001\u0000\u0000"+ + "\u0000\u01e9\u06e2\u0001\u0000\u0000\u0000\u01eb\u06e7\u0001\u0000\u0000"+ + "\u0000\u01ed\u06ec\u0001\u0000\u0000\u0000\u01ef\u06f0\u0001\u0000\u0000"+ + "\u0000\u01f1\u06f4\u0001\u0000\u0000\u0000\u01f3\u01f4\u0007\u0000\u0000"+ + "\u0000\u01f4\u01f5\u0007\u0001\u0000\u0000\u01f5\u01f6\u0007\u0002\u0000"+ + "\u0000\u01f6\u01f7\u0007\u0002\u0000\u0000\u01f7\u01f8\u0007\u0003\u0000"+ + "\u0000\u01f8\u01f9\u0007\u0004\u0000\u0000\u01f9\u01fa\u0007\u0005\u0000"+ + "\u0000\u01fa\u01fb\u0001\u0000\u0000\u0000\u01fb\u01fc\u0006\u0000\u0000"+ + "\u0000\u01fc\u0014\u0001\u0000\u0000\u0000\u01fd\u01fe\u0007\u0000\u0000"+ + "\u0000\u01fe\u01ff\u0007\u0006\u0000\u0000\u01ff\u0200\u0007\u0007\u0000"+ + "\u0000\u0200\u0201\u0007\b\u0000\u0000\u0201\u0202\u0001\u0000\u0000\u0000"+ + "\u0202\u0203\u0006\u0001\u0001\u0000\u0203\u0016\u0001\u0000\u0000\u0000"+ + "\u0204\u0205\u0007\u0003\u0000\u0000\u0205\u0206\u0007\t\u0000\u0000\u0206"+ + "\u0207\u0007\u0006\u0000\u0000\u0207\u0208\u0007\u0001\u0000\u0000\u0208"+ + "\u0209\u0007\u0004\u0000\u0000\u0209\u020a\u0007\n\u0000\u0000\u020a\u020b"+ + "\u0001\u0000\u0000\u0000\u020b\u020c\u0006\u0002\u0002\u0000\u020c\u0018"+ + "\u0001\u0000\u0000\u0000\u020d\u020e\u0007\u0003\u0000\u0000\u020e\u020f"+ + "\u0007\u000b\u0000\u0000\u020f\u0210\u0007\f\u0000\u0000\u0210\u0211\u0007"+ + "\r\u0000\u0000\u0211\u0212\u0001\u0000\u0000\u0000\u0212\u0213\u0006\u0003"+ + "\u0000\u0000\u0213\u001a\u0001\u0000\u0000\u0000\u0214\u0215\u0007\u0003"+ + "\u0000\u0000\u0215\u0216\u0007\u000e\u0000\u0000\u0216\u0217\u0007\b\u0000"+ + "\u0000\u0217\u0218\u0007\r\u0000\u0000\u0218\u0219\u0007\f\u0000\u0000"+ + "\u0219\u021a\u0007\u0001\u0000\u0000\u021a\u021b\u0007\t\u0000\u0000\u021b"+ + "\u021c\u0001\u0000\u0000\u0000\u021c\u021d\u0006\u0004\u0003\u0000\u021d"+ + "\u001c\u0001\u0000\u0000\u0000\u021e\u021f\u0007\u000f\u0000\u0000\u021f"+ + "\u0220\u0007\u0006\u0000\u0000\u0220\u0221\u0007\u0007\u0000\u0000\u0221"+ + "\u0222\u0007\u0010\u0000\u0000\u0222\u0223\u0001\u0000\u0000\u0000\u0223"+ + "\u0224\u0006\u0005\u0004\u0000\u0224\u001e\u0001\u0000\u0000\u0000\u0225"+ + "\u0226\u0007\u0011\u0000\u0000\u0226\u0227\u0007\u0006\u0000\u0000\u0227"+ + "\u0228\u0007\u0007\u0000\u0000\u0228\u0229\u0007\u0012\u0000\u0000\u0229"+ + "\u022a\u0001\u0000\u0000\u0000\u022a\u022b\u0006\u0006\u0000\u0000\u022b"+ + " \u0001\u0000\u0000\u0000\u022c\u022d\u0007\u0012\u0000\u0000\u022d\u022e"+ + "\u0007\u0003\u0000\u0000\u022e\u022f\u0007\u0003\u0000\u0000\u022f\u0230"+ + "\u0007\b\u0000\u0000\u0230\u0231\u0001\u0000\u0000\u0000\u0231\u0232\u0006"+ + "\u0007\u0001\u0000\u0232\"\u0001\u0000\u0000\u0000\u0233\u0234\u0007\r"+ + "\u0000\u0000\u0234\u0235\u0007\u0001\u0000\u0000\u0235\u0236\u0007\u0010"+ + "\u0000\u0000\u0236\u0237\u0007\u0001\u0000\u0000\u0237\u0238\u0007\u0005"+ + "\u0000\u0000\u0238\u0239\u0001\u0000\u0000\u0000\u0239\u023a\u0006\b\u0000"+ + "\u0000\u023a$\u0001\u0000\u0000\u0000\u023b\u023c\u0007\u0010\u0000\u0000"+ + "\u023c\u023d\u0007\u000b\u0000\u0000\u023d\u023e\u0005_\u0000\u0000\u023e"+ + "\u023f\u0007\u0003\u0000\u0000\u023f\u0240\u0007\u000e\u0000\u0000\u0240"+ + "\u0241\u0007\b\u0000\u0000\u0241\u0242\u0007\f\u0000\u0000\u0242\u0243"+ + "\u0007\t\u0000\u0000\u0243\u0244\u0007\u0000\u0000\u0000\u0244\u0245\u0001"+ + "\u0000\u0000\u0000\u0245\u0246\u0006\t\u0005\u0000\u0246&\u0001\u0000"+ + "\u0000\u0000\u0247\u0248\u0007\u0006\u0000\u0000\u0248\u0249\u0007\u0003"+ + "\u0000\u0000\u0249\u024a\u0007\t\u0000\u0000\u024a\u024b\u0007\f\u0000"+ + "\u0000\u024b\u024c\u0007\u0010\u0000\u0000\u024c\u024d\u0007\u0003\u0000"+ + "\u0000\u024d\u024e\u0001\u0000\u0000\u0000\u024e\u024f\u0006\n\u0006\u0000"+ + "\u024f(\u0001\u0000\u0000\u0000\u0250\u0251\u0007\u0006\u0000\u0000\u0251"+ + "\u0252\u0007\u0007\u0000\u0000\u0252\u0253\u0007\u0013\u0000\u0000\u0253"+ + "\u0254\u0001\u0000\u0000\u0000\u0254\u0255\u0006\u000b\u0000\u0000\u0255"+ + "*\u0001\u0000\u0000\u0000\u0256\u0257\u0007\u0002\u0000\u0000\u0257\u0258"+ + "\u0007\n\u0000\u0000\u0258\u0259\u0007\u0007\u0000\u0000\u0259\u025a\u0007"+ + "\u0013\u0000\u0000\u025a\u025b\u0001\u0000\u0000\u0000\u025b\u025c\u0006"+ + "\f\u0007\u0000\u025c,\u0001\u0000\u0000\u0000\u025d\u025e\u0007\u0002"+ + "\u0000\u0000\u025e\u025f\u0007\u0007\u0000\u0000\u025f\u0260\u0007\u0006"+ + "\u0000\u0000\u0260\u0261\u0007\u0005\u0000\u0000\u0261\u0262\u0001\u0000"+ + "\u0000\u0000\u0262\u0263\u0006\r\u0000\u0000\u0263.\u0001\u0000\u0000"+ + "\u0000\u0264\u0265\u0007\u0002\u0000\u0000\u0265\u0266\u0007\u0005\u0000"+ + "\u0000\u0266\u0267\u0007\f\u0000\u0000\u0267\u0268\u0007\u0005\u0000\u0000"+ + "\u0268\u0269\u0007\u0002\u0000\u0000\u0269\u026a\u0001\u0000\u0000\u0000"+ + "\u026a\u026b\u0006\u000e\u0000\u0000\u026b0\u0001\u0000\u0000\u0000\u026c"+ + "\u026d\u0007\u0013\u0000\u0000\u026d\u026e\u0007\n\u0000\u0000\u026e\u026f"+ + "\u0007\u0003\u0000\u0000\u026f\u0270\u0007\u0006\u0000\u0000\u0270\u0271"+ + "\u0007\u0003\u0000\u0000\u0271\u0272\u0001\u0000\u0000\u0000\u0272\u0273"+ + "\u0006\u000f\u0000\u0000\u02732\u0001\u0000\u0000\u0000\u0274\u0275\u0007"+ + "\r\u0000\u0000\u0275\u0276\u0007\u0007\u0000\u0000\u0276\u0277\u0007\u0007"+ + "\u0000\u0000\u0277\u0278\u0007\u0012\u0000\u0000\u0278\u0279\u0007\u0014"+ + "\u0000\u0000\u0279\u027a\u0007\b\u0000\u0000\u027a\u027b\u0001\u0000\u0000"+ + "\u0000\u027b\u027c\u0006\u0010\b\u0000\u027c4\u0001\u0000\u0000\u0000"+ + "\u027d\u027e\u0004\u0011\u0000\u0000\u027e\u027f\u0007\u0004\u0000\u0000"+ + "\u027f\u0280\u0007\n\u0000\u0000\u0280\u0281\u0007\f\u0000\u0000\u0281"+ + "\u0282\u0007\t\u0000\u0000\u0282\u0283\u0007\u0011\u0000\u0000\u0283\u0284"+ + "\u0007\u0003\u0000\u0000\u0284\u0285\u0005_\u0000\u0000\u0285\u0286\u0007"+ + "\b\u0000\u0000\u0286\u0287\u0007\u0007\u0000\u0000\u0287\u0288\u0007\u0001"+ + "\u0000\u0000\u0288\u0289\u0007\t\u0000\u0000\u0289\u028a\u0007\u0005\u0000"+ + "\u0000\u028a\u028b\u0001\u0000\u0000\u0000\u028b\u028c\u0006\u0011\t\u0000"+ + "\u028c6\u0001\u0000\u0000\u0000\u028d\u028e\u0004\u0012\u0001\u0000\u028e"+ + "\u028f\u0007\u0001\u0000\u0000\u028f\u0290\u0007\t\u0000\u0000\u0290\u0291"+ + "\u0007\r\u0000\u0000\u0291\u0292\u0007\u0001\u0000\u0000\u0292\u0293\u0007"+ + "\t\u0000\u0000\u0293\u0294\u0007\u0003\u0000\u0000\u0294\u0295\u0007\u0002"+ + "\u0000\u0000\u0295\u0296\u0007\u0005\u0000\u0000\u0296\u0297\u0007\f\u0000"+ + "\u0000\u0297\u0298\u0007\u0005\u0000\u0000\u0298\u0299\u0007\u0002\u0000"+ + "\u0000\u0299\u029a\u0001\u0000\u0000\u0000\u029a\u029b\u0006\u0012\u0000"+ + "\u0000\u029b8\u0001\u0000\u0000\u0000\u029c\u029d\u0004\u0013\u0002\u0000"+ + "\u029d\u029e\u0007\u0001\u0000\u0000\u029e\u029f\u0007\t\u0000\u0000\u029f"+ + "\u02a0\u0007\u0002\u0000\u0000\u02a0\u02a1\u0007\u0001\u0000\u0000\u02a1"+ + "\u02a2\u0007\u0002\u0000\u0000\u02a2\u02a3\u0007\u0005\u0000\u0000\u02a3"+ + "\u02a4\u0005_\u0000\u0000\u02a4\u02a5\u0005\u8001\uf414\u0000\u0000\u02a5"+ + "\u02a6\u0001\u0000\u0000\u0000\u02a6\u02a7\u0006\u0013\u0001\u0000\u02a7"+ + ":\u0001\u0000\u0000\u0000\u02a8\u02a9\u0004\u0014\u0003\u0000\u02a9\u02aa"+ + "\u0007\r\u0000\u0000\u02aa\u02ab\u0007\u0007\u0000\u0000\u02ab\u02ac\u0007"+ + "\u0007\u0000\u0000\u02ac\u02ad\u0007\u0012\u0000\u0000\u02ad\u02ae\u0007"+ + "\u0014\u0000\u0000\u02ae\u02af\u0007\b\u0000\u0000\u02af\u02b0\u0005_"+ + "\u0000\u0000\u02b0\u02b1\u0005\u8001\uf414\u0000\u0000\u02b1\u02b2\u0001"+ + "\u0000\u0000\u0000\u02b2\u02b3\u0006\u0014\n\u0000\u02b3<\u0001\u0000"+ + "\u0000\u0000\u02b4\u02b5\u0004\u0015\u0004\u0000\u02b5\u02b6\u0007\u0010"+ + "\u0000\u0000\u02b6\u02b7\u0007\u0003\u0000\u0000\u02b7\u02b8\u0007\u0005"+ + "\u0000\u0000\u02b8\u02b9\u0007\u0006\u0000\u0000\u02b9\u02ba\u0007\u0001"+ + "\u0000\u0000\u02ba\u02bb\u0007\u0004\u0000\u0000\u02bb\u02bc\u0007\u0002"+ + "\u0000\u0000\u02bc\u02bd\u0001\u0000\u0000\u0000\u02bd\u02be\u0006\u0015"+ + "\u000b\u0000\u02be>\u0001\u0000\u0000\u0000\u02bf\u02c0\u0004\u0016\u0005"+ + "\u0000\u02c0\u02c1\u0007\u000f\u0000\u0000\u02c1\u02c2\u0007\u0014\u0000"+ + "\u0000\u02c2\u02c3\u0007\r\u0000\u0000\u02c3\u02c4\u0007\r\u0000\u0000"+ + "\u02c4\u02c5\u0001\u0000\u0000\u0000\u02c5\u02c6\u0006\u0016\b\u0000\u02c6"+ + "@\u0001\u0000\u0000\u0000\u02c7\u02c8\u0004\u0017\u0006\u0000\u02c8\u02c9"+ + "\u0007\r\u0000\u0000\u02c9\u02ca\u0007\u0003\u0000\u0000\u02ca\u02cb\u0007"+ + "\u000f\u0000\u0000\u02cb\u02cc\u0007\u0005\u0000\u0000\u02cc\u02cd\u0001"+ + "\u0000\u0000\u0000\u02cd\u02ce\u0006\u0017\b\u0000\u02ceB\u0001\u0000"+ + "\u0000\u0000\u02cf\u02d0\u0004\u0018\u0007\u0000\u02d0\u02d1\u0007\u0006"+ + "\u0000\u0000\u02d1\u02d2\u0007\u0001\u0000\u0000\u02d2\u02d3\u0007\u0011"+ + "\u0000\u0000\u02d3\u02d4\u0007\n\u0000\u0000\u02d4\u02d5\u0007\u0005\u0000"+ + "\u0000\u02d5\u02d6\u0001\u0000\u0000\u0000\u02d6\u02d7\u0006\u0018\b\u0000"+ + "\u02d7D\u0001\u0000\u0000\u0000\u02d8\u02d9\u0004\u0019\b\u0000\u02d9"+ + "\u02da\u0007\u000f\u0000\u0000\u02da\u02db\u0007\u0007\u0000\u0000\u02db"+ + "\u02dc\u0007\u0006\u0000\u0000\u02dc\u02dd\u0007\u0012\u0000\u0000\u02dd"+ + "\u02de\u0001\u0000\u0000\u0000\u02de\u02df\u0006\u0019\f\u0000\u02dfF"+ + "\u0001\u0000\u0000\u0000\u02e0\u02e2\b\u0015\u0000\u0000\u02e1\u02e0\u0001"+ + "\u0000\u0000\u0000\u02e2\u02e3\u0001\u0000\u0000\u0000\u02e3\u02e1\u0001"+ + "\u0000\u0000\u0000\u02e3\u02e4\u0001\u0000\u0000\u0000\u02e4\u02e5\u0001"+ + "\u0000\u0000\u0000\u02e5\u02e6\u0006\u001a\u0000\u0000\u02e6H\u0001\u0000"+ + "\u0000\u0000\u02e7\u02e8\u0005/\u0000\u0000\u02e8\u02e9\u0005/\u0000\u0000"+ + "\u02e9\u02ed\u0001\u0000\u0000\u0000\u02ea\u02ec\b\u0016\u0000\u0000\u02eb"+ + "\u02ea\u0001\u0000\u0000\u0000\u02ec\u02ef\u0001\u0000\u0000\u0000\u02ed"+ + "\u02eb\u0001\u0000\u0000\u0000\u02ed\u02ee\u0001\u0000\u0000\u0000\u02ee"+ + "\u02f1\u0001\u0000\u0000\u0000\u02ef\u02ed\u0001\u0000\u0000\u0000\u02f0"+ + "\u02f2\u0005\r\u0000\u0000\u02f1\u02f0\u0001\u0000\u0000\u0000\u02f1\u02f2"+ + "\u0001\u0000\u0000\u0000\u02f2\u02f4\u0001\u0000\u0000\u0000\u02f3\u02f5"+ + "\u0005\n\u0000\u0000\u02f4\u02f3\u0001\u0000\u0000\u0000\u02f4\u02f5\u0001"+ + "\u0000\u0000\u0000\u02f5\u02f6\u0001\u0000\u0000\u0000\u02f6\u02f7\u0006"+ + "\u001b\r\u0000\u02f7J\u0001\u0000\u0000\u0000\u02f8\u02f9\u0005/\u0000"+ + "\u0000\u02f9\u02fa\u0005*\u0000\u0000\u02fa\u02ff\u0001\u0000\u0000\u0000"+ + "\u02fb\u02fe\u0003K\u001c\u0000\u02fc\u02fe\t\u0000\u0000\u0000\u02fd"+ + "\u02fb\u0001\u0000\u0000\u0000\u02fd\u02fc\u0001\u0000\u0000\u0000\u02fe"+ + "\u0301\u0001\u0000\u0000\u0000\u02ff\u0300\u0001\u0000\u0000\u0000\u02ff"+ + "\u02fd\u0001\u0000\u0000\u0000\u0300\u0302\u0001\u0000\u0000\u0000\u0301"+ + "\u02ff\u0001\u0000\u0000\u0000\u0302\u0303\u0005*\u0000\u0000\u0303\u0304"+ + "\u0005/\u0000\u0000\u0304\u0305\u0001\u0000\u0000\u0000\u0305\u0306\u0006"+ + "\u001c\r\u0000\u0306L\u0001\u0000\u0000\u0000\u0307\u0309\u0007\u0017"+ + "\u0000\u0000\u0308\u0307\u0001\u0000\u0000\u0000\u0309\u030a\u0001\u0000"+ + "\u0000\u0000\u030a\u0308\u0001\u0000\u0000\u0000\u030a\u030b\u0001\u0000"+ + "\u0000\u0000\u030b\u030c\u0001\u0000\u0000\u0000\u030c\u030d\u0006\u001d"+ + "\r\u0000\u030dN\u0001\u0000\u0000\u0000\u030e\u030f\u0005|\u0000\u0000"+ + "\u030f\u0310\u0001\u0000\u0000\u0000\u0310\u0311\u0006\u001e\u000e\u0000"+ + "\u0311P\u0001\u0000\u0000\u0000\u0312\u0313\u0007\u0018\u0000\u0000\u0313"+ + "R\u0001\u0000\u0000\u0000\u0314\u0315\u0007\u0019\u0000\u0000\u0315T\u0001"+ + "\u0000\u0000\u0000\u0316\u0317\u0005\\\u0000\u0000\u0317\u0318\u0007\u001a"+ + "\u0000\u0000\u0318V\u0001\u0000\u0000\u0000\u0319\u031a\b\u001b\u0000"+ + "\u0000\u031aX\u0001\u0000\u0000\u0000\u031b\u031d\u0007\u0003\u0000\u0000"+ + "\u031c\u031e\u0007\u001c\u0000\u0000\u031d\u031c\u0001\u0000\u0000\u0000"+ + "\u031d\u031e\u0001\u0000\u0000\u0000\u031e\u0320\u0001\u0000\u0000\u0000"+ + "\u031f\u0321\u0003Q\u001f\u0000\u0320\u031f\u0001\u0000\u0000\u0000\u0321"+ + "\u0322\u0001\u0000\u0000\u0000\u0322\u0320\u0001\u0000\u0000\u0000\u0322"+ + "\u0323\u0001\u0000\u0000\u0000\u0323Z\u0001\u0000\u0000\u0000\u0324\u0325"+ + "\u0005@\u0000\u0000\u0325\\\u0001\u0000\u0000\u0000\u0326\u0327\u0005"+ + "`\u0000\u0000\u0327^\u0001\u0000\u0000\u0000\u0328\u032c\b\u001d\u0000"+ + "\u0000\u0329\u032a\u0005`\u0000\u0000\u032a\u032c\u0005`\u0000\u0000\u032b"+ + "\u0328\u0001\u0000\u0000\u0000\u032b\u0329\u0001\u0000\u0000\u0000\u032c"+ + "`\u0001\u0000\u0000\u0000\u032d\u032e\u0005_\u0000\u0000\u032eb\u0001"+ + "\u0000\u0000\u0000\u032f\u0333\u0003S \u0000\u0330\u0333\u0003Q\u001f"+ + "\u0000\u0331\u0333\u0003a\'\u0000\u0332\u032f\u0001\u0000\u0000\u0000"+ + "\u0332\u0330\u0001\u0000\u0000\u0000\u0332\u0331\u0001\u0000\u0000\u0000"+ + "\u0333d\u0001\u0000\u0000\u0000\u0334\u0339\u0005\"\u0000\u0000\u0335"+ + "\u0338\u0003U!\u0000\u0336\u0338\u0003W\"\u0000\u0337\u0335\u0001\u0000"+ + "\u0000\u0000\u0337\u0336\u0001\u0000\u0000\u0000\u0338\u033b\u0001\u0000"+ + "\u0000\u0000\u0339\u0337\u0001\u0000\u0000\u0000\u0339\u033a\u0001\u0000"+ + "\u0000\u0000\u033a\u033c\u0001\u0000\u0000\u0000\u033b\u0339\u0001\u0000"+ + "\u0000\u0000\u033c\u0352\u0005\"\u0000\u0000\u033d\u033e\u0005\"\u0000"+ + "\u0000\u033e\u033f\u0005\"\u0000\u0000\u033f\u0340\u0005\"\u0000\u0000"+ + "\u0340\u0344\u0001\u0000\u0000\u0000\u0341\u0343\b\u0016\u0000\u0000\u0342"+ + "\u0341\u0001\u0000\u0000\u0000\u0343\u0346\u0001\u0000\u0000\u0000\u0344"+ + "\u0345\u0001\u0000\u0000\u0000\u0344\u0342\u0001\u0000\u0000\u0000\u0345"+ + "\u0347\u0001\u0000\u0000\u0000\u0346\u0344\u0001\u0000\u0000\u0000\u0347"+ + "\u0348\u0005\"\u0000\u0000\u0348\u0349\u0005\"\u0000\u0000\u0349\u034a"+ + "\u0005\"\u0000\u0000\u034a\u034c\u0001\u0000\u0000\u0000\u034b\u034d\u0005"+ + "\"\u0000\u0000\u034c\u034b\u0001\u0000\u0000\u0000\u034c\u034d\u0001\u0000"+ + "\u0000\u0000\u034d\u034f\u0001\u0000\u0000\u0000\u034e\u0350\u0005\"\u0000"+ + "\u0000\u034f\u034e\u0001\u0000\u0000\u0000\u034f\u0350\u0001\u0000\u0000"+ + "\u0000\u0350\u0352\u0001\u0000\u0000\u0000\u0351\u0334\u0001\u0000\u0000"+ + "\u0000\u0351\u033d\u0001\u0000\u0000\u0000\u0352f\u0001\u0000\u0000\u0000"+ + "\u0353\u0355\u0003Q\u001f\u0000\u0354\u0353\u0001\u0000\u0000\u0000\u0355"+ + "\u0356\u0001\u0000\u0000\u0000\u0356\u0354\u0001\u0000\u0000\u0000\u0356"+ + "\u0357\u0001\u0000\u0000\u0000\u0357h\u0001\u0000\u0000\u0000\u0358\u035a"+ + "\u0003Q\u001f\u0000\u0359\u0358\u0001\u0000\u0000\u0000\u035a\u035b\u0001"+ + "\u0000\u0000\u0000\u035b\u0359\u0001\u0000\u0000\u0000\u035b\u035c\u0001"+ + "\u0000\u0000\u0000\u035c\u035d\u0001\u0000\u0000\u0000\u035d\u0361\u0003"+ + "{4\u0000\u035e\u0360\u0003Q\u001f\u0000\u035f\u035e\u0001\u0000\u0000"+ + "\u0000\u0360\u0363\u0001\u0000\u0000\u0000\u0361\u035f\u0001\u0000\u0000"+ + "\u0000\u0361\u0362\u0001\u0000\u0000\u0000\u0362\u0383\u0001\u0000\u0000"+ + "\u0000\u0363\u0361\u0001\u0000\u0000\u0000\u0364\u0366\u0003{4\u0000\u0365"+ + "\u0367\u0003Q\u001f\u0000\u0366\u0365\u0001\u0000\u0000\u0000\u0367\u0368"+ + "\u0001\u0000\u0000\u0000\u0368\u0366\u0001\u0000\u0000\u0000\u0368\u0369"+ + "\u0001\u0000\u0000\u0000\u0369\u0383\u0001\u0000\u0000\u0000\u036a\u036c"+ + "\u0003Q\u001f\u0000\u036b\u036a\u0001\u0000\u0000\u0000\u036c\u036d\u0001"+ + "\u0000\u0000\u0000\u036d\u036b\u0001\u0000\u0000\u0000\u036d\u036e\u0001"+ + "\u0000\u0000\u0000\u036e\u0376\u0001\u0000\u0000\u0000\u036f\u0373\u0003"+ + "{4\u0000\u0370\u0372\u0003Q\u001f\u0000\u0371\u0370\u0001\u0000\u0000"+ + "\u0000\u0372\u0375\u0001\u0000\u0000\u0000\u0373\u0371\u0001\u0000\u0000"+ + "\u0000\u0373\u0374\u0001\u0000\u0000\u0000\u0374\u0377\u0001\u0000\u0000"+ + "\u0000\u0375\u0373\u0001\u0000\u0000\u0000\u0376\u036f\u0001\u0000\u0000"+ + "\u0000\u0376\u0377\u0001\u0000\u0000\u0000\u0377\u0378\u0001\u0000\u0000"+ + "\u0000\u0378\u0379\u0003Y#\u0000\u0379\u0383\u0001\u0000\u0000\u0000\u037a"+ + "\u037c\u0003{4\u0000\u037b\u037d\u0003Q\u001f\u0000\u037c\u037b\u0001"+ + "\u0000\u0000\u0000\u037d\u037e\u0001\u0000\u0000\u0000\u037e\u037c\u0001"+ + "\u0000\u0000\u0000\u037e\u037f\u0001\u0000\u0000\u0000\u037f\u0380\u0001"+ + "\u0000\u0000\u0000\u0380\u0381\u0003Y#\u0000\u0381\u0383\u0001\u0000\u0000"+ + "\u0000\u0382\u0359\u0001\u0000\u0000\u0000\u0382\u0364\u0001\u0000\u0000"+ + "\u0000\u0382\u036b\u0001\u0000\u0000\u0000\u0382\u037a\u0001\u0000\u0000"+ + "\u0000\u0383j\u0001\u0000\u0000\u0000\u0384\u0385\u0007\u001e\u0000\u0000"+ + "\u0385\u0386\u0007\u001f\u0000\u0000\u0386l\u0001\u0000\u0000\u0000\u0387"+ + "\u0388\u0007\f\u0000\u0000\u0388\u0389\u0007\t\u0000\u0000\u0389\u038a"+ + "\u0007\u0000\u0000\u0000\u038an\u0001\u0000\u0000\u0000\u038b\u038c\u0007"+ + "\f\u0000\u0000\u038c\u038d\u0007\u0002\u0000\u0000\u038d\u038e\u0007\u0004"+ + "\u0000\u0000\u038ep\u0001\u0000\u0000\u0000\u038f\u0390\u0005=\u0000\u0000"+ + "\u0390r\u0001\u0000\u0000\u0000\u0391\u0392\u0005:\u0000\u0000\u0392\u0393"+ + "\u0005:\u0000\u0000\u0393t\u0001\u0000\u0000\u0000\u0394\u0395\u0005:"+ + "\u0000\u0000\u0395v\u0001\u0000\u0000\u0000\u0396\u0397\u0005,\u0000\u0000"+ + "\u0397x\u0001\u0000\u0000\u0000\u0398\u0399\u0007\u0000\u0000\u0000\u0399"+ + "\u039a\u0007\u0003\u0000\u0000\u039a\u039b\u0007\u0002\u0000\u0000\u039b"+ + "\u039c\u0007\u0004\u0000\u0000\u039cz\u0001\u0000\u0000\u0000\u039d\u039e"+ + "\u0005.\u0000\u0000\u039e|\u0001\u0000\u0000\u0000\u039f\u03a0\u0007\u000f"+ + "\u0000\u0000\u03a0\u03a1\u0007\f\u0000\u0000\u03a1\u03a2\u0007\r\u0000"+ + "\u0000\u03a2\u03a3\u0007\u0002\u0000\u0000\u03a3\u03a4\u0007\u0003\u0000"+ + "\u0000\u03a4~\u0001\u0000\u0000\u0000\u03a5\u03a6\u0007\u000f\u0000\u0000"+ + "\u03a6\u03a7\u0007\u0001\u0000\u0000\u03a7\u03a8\u0007\u0006\u0000\u0000"+ + "\u03a8\u03a9\u0007\u0002\u0000\u0000\u03a9\u03aa\u0007\u0005\u0000\u0000"+ + "\u03aa\u0080\u0001\u0000\u0000\u0000\u03ab\u03ac\u0007\u0001\u0000\u0000"+ + "\u03ac\u03ad\u0007\t\u0000\u0000\u03ad\u0082\u0001\u0000\u0000\u0000\u03ae"+ + "\u03af\u0007\u0001\u0000\u0000\u03af\u03b0\u0007\u0002\u0000\u0000\u03b0"+ + "\u0084\u0001\u0000\u0000\u0000\u03b1\u03b2\u0007\r\u0000\u0000\u03b2\u03b3"+ + "\u0007\f\u0000\u0000\u03b3\u03b4\u0007\u0002\u0000\u0000\u03b4\u03b5\u0007"+ + "\u0005\u0000\u0000\u03b5\u0086\u0001\u0000\u0000\u0000\u03b6\u03b7\u0007"+ + "\r\u0000\u0000\u03b7\u03b8\u0007\u0001\u0000\u0000\u03b8\u03b9\u0007\u0012"+ + "\u0000\u0000\u03b9\u03ba\u0007\u0003\u0000\u0000\u03ba\u0088\u0001\u0000"+ + "\u0000\u0000\u03bb\u03bc\u0007\t\u0000\u0000\u03bc\u03bd\u0007\u0007\u0000"+ + "\u0000\u03bd\u03be\u0007\u0005\u0000\u0000\u03be\u008a\u0001\u0000\u0000"+ + "\u0000\u03bf\u03c0\u0007\t\u0000\u0000\u03c0\u03c1\u0007\u0014\u0000\u0000"+ + "\u03c1\u03c2\u0007\r\u0000\u0000\u03c2\u03c3\u0007\r\u0000\u0000\u03c3"+ + "\u008c\u0001\u0000\u0000\u0000\u03c4\u03c5\u0007\t\u0000\u0000\u03c5\u03c6"+ + "\u0007\u0014\u0000\u0000\u03c6\u03c7\u0007\r\u0000\u0000\u03c7\u03c8\u0007"+ + "\r\u0000\u0000\u03c8\u03c9\u0007\u0002\u0000\u0000\u03c9\u008e\u0001\u0000"+ + "\u0000\u0000\u03ca\u03cb\u0007\u0007\u0000\u0000\u03cb\u03cc\u0007\u0006"+ + "\u0000\u0000\u03cc\u0090\u0001\u0000\u0000\u0000\u03cd\u03ce\u0005?\u0000"+ + "\u0000\u03ce\u0092\u0001\u0000\u0000\u0000\u03cf\u03d0\u0007\u0006\u0000"+ + "\u0000\u03d0\u03d1\u0007\r\u0000\u0000\u03d1\u03d2\u0007\u0001\u0000\u0000"+ + "\u03d2\u03d3\u0007\u0012\u0000\u0000\u03d3\u03d4\u0007\u0003\u0000\u0000"+ + "\u03d4\u0094\u0001\u0000\u0000\u0000\u03d5\u03d6\u0007\u0005\u0000\u0000"+ + "\u03d6\u03d7\u0007\u0006\u0000\u0000\u03d7\u03d8\u0007\u0014\u0000\u0000"+ + "\u03d8\u03d9\u0007\u0003\u0000\u0000\u03d9\u0096\u0001\u0000\u0000\u0000"+ + "\u03da\u03db\u0005=\u0000\u0000\u03db\u03dc\u0005=\u0000\u0000\u03dc\u0098"+ + "\u0001\u0000\u0000\u0000\u03dd\u03de\u0005=\u0000\u0000\u03de\u03df\u0005"+ + "~\u0000\u0000\u03df\u009a\u0001\u0000\u0000\u0000\u03e0\u03e1\u0005!\u0000"+ + "\u0000\u03e1\u03e2\u0005=\u0000\u0000\u03e2\u009c\u0001\u0000\u0000\u0000"+ + "\u03e3\u03e4\u0005<\u0000\u0000\u03e4\u009e\u0001\u0000\u0000\u0000\u03e5"+ + "\u03e6\u0005<\u0000\u0000\u03e6\u03e7\u0005=\u0000\u0000\u03e7\u00a0\u0001"+ + "\u0000\u0000\u0000\u03e8\u03e9\u0005>\u0000\u0000\u03e9\u00a2\u0001\u0000"+ + "\u0000\u0000\u03ea\u03eb\u0005>\u0000\u0000\u03eb\u03ec\u0005=\u0000\u0000"+ + "\u03ec\u00a4\u0001\u0000\u0000\u0000\u03ed\u03ee\u0005+\u0000\u0000\u03ee"+ + "\u00a6\u0001\u0000\u0000\u0000\u03ef\u03f0\u0005-\u0000\u0000\u03f0\u00a8"+ + "\u0001\u0000\u0000\u0000\u03f1\u03f2\u0005*\u0000\u0000\u03f2\u00aa\u0001"+ + "\u0000\u0000\u0000\u03f3\u03f4\u0005/\u0000\u0000\u03f4\u00ac\u0001\u0000"+ + "\u0000\u0000\u03f5\u03f6\u0005%\u0000\u0000\u03f6\u00ae\u0001\u0000\u0000"+ + "\u0000\u03f7\u03f8\u0005{\u0000\u0000\u03f8\u00b0\u0001\u0000\u0000\u0000"+ + "\u03f9\u03fa\u0005}\u0000\u0000\u03fa\u00b2\u0001\u0000\u0000\u0000\u03fb"+ + "\u03fc\u00031\u000f\u0000\u03fc\u03fd\u0001\u0000\u0000\u0000\u03fd\u03fe"+ + "\u0006P\u000f\u0000\u03fe\u00b4\u0001\u0000\u0000\u0000\u03ff\u0402\u0003"+ + "\u0091?\u0000\u0400\u0403\u0003S \u0000\u0401\u0403\u0003a\'\u0000\u0402"+ + "\u0400\u0001\u0000\u0000\u0000\u0402\u0401\u0001\u0000\u0000\u0000\u0403"+ + "\u0407\u0001\u0000\u0000\u0000\u0404\u0406\u0003c(\u0000\u0405\u0404\u0001"+ + "\u0000\u0000\u0000\u0406\u0409\u0001\u0000\u0000\u0000\u0407\u0405\u0001"+ + "\u0000\u0000\u0000\u0407\u0408\u0001\u0000\u0000\u0000\u0408\u0411\u0001"+ + "\u0000\u0000\u0000\u0409\u0407\u0001\u0000\u0000\u0000\u040a\u040c\u0003"+ + "\u0091?\u0000\u040b\u040d\u0003Q\u001f\u0000\u040c\u040b\u0001\u0000\u0000"+ + "\u0000\u040d\u040e\u0001\u0000\u0000\u0000\u040e\u040c\u0001\u0000\u0000"+ + "\u0000\u040e\u040f\u0001\u0000\u0000\u0000\u040f\u0411\u0001\u0000\u0000"+ + "\u0000\u0410\u03ff\u0001\u0000\u0000\u0000\u0410\u040a\u0001\u0000\u0000"+ + "\u0000\u0411\u00b6\u0001\u0000\u0000\u0000\u0412\u0413\u0005[\u0000\u0000"+ + "\u0413\u0414\u0001\u0000\u0000\u0000\u0414\u0415\u0006R\u0000\u0000\u0415"+ + "\u0416\u0006R\u0000\u0000\u0416\u00b8\u0001\u0000\u0000\u0000\u0417\u0418"+ + "\u0005]\u0000\u0000\u0418\u0419\u0001\u0000\u0000\u0000\u0419\u041a\u0006"+ + "S\u000e\u0000\u041a\u041b\u0006S\u000e\u0000\u041b\u00ba\u0001\u0000\u0000"+ + "\u0000\u041c\u041d\u0005(\u0000\u0000\u041d\u041e\u0001\u0000\u0000\u0000"+ + "\u041e\u041f\u0006T\u0000\u0000\u041f\u0420\u0006T\u0000\u0000\u0420\u00bc"+ + "\u0001\u0000\u0000\u0000\u0421\u0422\u0005)\u0000\u0000\u0422\u0423\u0001"+ + "\u0000\u0000\u0000\u0423\u0424\u0006U\u000e\u0000\u0424\u0425\u0006U\u000e"+ + "\u0000\u0425\u00be\u0001\u0000\u0000\u0000\u0426\u042a\u0003S \u0000\u0427"+ + "\u0429\u0003c(\u0000\u0428\u0427\u0001\u0000\u0000\u0000\u0429\u042c\u0001"+ + "\u0000\u0000\u0000\u042a\u0428\u0001\u0000\u0000\u0000\u042a\u042b\u0001"+ + "\u0000\u0000\u0000\u042b\u0437\u0001\u0000\u0000\u0000\u042c\u042a\u0001"+ + "\u0000\u0000\u0000\u042d\u0430\u0003a\'\u0000\u042e\u0430\u0003[$\u0000"+ + "\u042f\u042d\u0001\u0000\u0000\u0000\u042f\u042e\u0001\u0000\u0000\u0000"+ + "\u0430\u0432\u0001\u0000\u0000\u0000\u0431\u0433\u0003c(\u0000\u0432\u0431"+ + "\u0001\u0000\u0000\u0000\u0433\u0434\u0001\u0000\u0000\u0000\u0434\u0432"+ + "\u0001\u0000\u0000\u0000\u0434\u0435\u0001\u0000\u0000\u0000\u0435\u0437"+ + "\u0001\u0000\u0000\u0000\u0436\u0426\u0001\u0000\u0000\u0000\u0436\u042f"+ + "\u0001\u0000\u0000\u0000\u0437\u00c0\u0001\u0000\u0000\u0000\u0438\u043a"+ + "\u0003]%\u0000\u0439\u043b\u0003_&\u0000\u043a\u0439\u0001\u0000\u0000"+ + "\u0000\u043b\u043c\u0001\u0000\u0000\u0000\u043c\u043a\u0001\u0000\u0000"+ + "\u0000\u043c\u043d\u0001\u0000\u0000\u0000\u043d\u043e\u0001\u0000\u0000"+ + "\u0000\u043e\u043f\u0003]%\u0000\u043f\u00c2\u0001\u0000\u0000\u0000\u0440"+ + "\u0441\u0003\u00c1W\u0000\u0441\u00c4\u0001\u0000\u0000\u0000\u0442\u0443"+ + "\u0003I\u001b\u0000\u0443\u0444\u0001\u0000\u0000\u0000\u0444\u0445\u0006"+ + "Y\r\u0000\u0445\u00c6\u0001\u0000\u0000\u0000\u0446\u0447\u0003K\u001c"+ + "\u0000\u0447\u0448\u0001\u0000\u0000\u0000\u0448\u0449\u0006Z\r\u0000"+ + "\u0449\u00c8\u0001\u0000\u0000\u0000\u044a\u044b\u0003M\u001d\u0000\u044b"+ + "\u044c\u0001\u0000\u0000\u0000\u044c\u044d\u0006[\r\u0000\u044d\u00ca"+ + "\u0001\u0000\u0000\u0000\u044e\u044f\u0003\u00b7R\u0000\u044f\u0450\u0001"+ + "\u0000\u0000\u0000\u0450\u0451\u0006\\\u0010\u0000\u0451\u0452\u0006\\"+ + "\u0011\u0000\u0452\u00cc\u0001\u0000\u0000\u0000\u0453\u0454\u0003O\u001e"+ + "\u0000\u0454\u0455\u0001\u0000\u0000\u0000\u0455\u0456\u0006]\u0012\u0000"+ + "\u0456\u0457\u0006]\u000e\u0000\u0457\u00ce\u0001\u0000\u0000\u0000\u0458"+ + "\u0459\u0003M\u001d\u0000\u0459\u045a\u0001\u0000\u0000\u0000\u045a\u045b"+ + "\u0006^\r\u0000\u045b\u00d0\u0001\u0000\u0000\u0000\u045c\u045d\u0003"+ + "I\u001b\u0000\u045d\u045e\u0001\u0000\u0000\u0000\u045e\u045f\u0006_\r"+ + "\u0000\u045f\u00d2\u0001\u0000\u0000\u0000\u0460\u0461\u0003K\u001c\u0000"+ + "\u0461\u0462\u0001\u0000\u0000\u0000\u0462\u0463\u0006`\r\u0000\u0463"+ + "\u00d4\u0001\u0000\u0000\u0000\u0464\u0465\u0003O\u001e\u0000\u0465\u0466"+ + "\u0001\u0000\u0000\u0000\u0466\u0467\u0006a\u0012\u0000\u0467\u0468\u0006"+ + "a\u000e\u0000\u0468\u00d6\u0001\u0000\u0000\u0000\u0469\u046a\u0003\u00b7"+ + "R\u0000\u046a\u046b\u0001\u0000\u0000\u0000\u046b\u046c\u0006b\u0010\u0000"+ + "\u046c\u00d8\u0001\u0000\u0000\u0000\u046d\u046e\u0003\u00b9S\u0000\u046e"+ + "\u046f\u0001\u0000\u0000\u0000\u046f\u0470\u0006c\u0013\u0000\u0470\u00da"+ + "\u0001\u0000\u0000\u0000\u0471\u0472\u0003u1\u0000\u0472\u0473\u0001\u0000"+ + "\u0000\u0000\u0473\u0474\u0006d\u0014\u0000\u0474\u00dc\u0001\u0000\u0000"+ + "\u0000\u0475\u0476\u0003w2\u0000\u0476\u0477\u0001\u0000\u0000\u0000\u0477"+ + "\u0478\u0006e\u0015\u0000\u0478\u00de\u0001\u0000\u0000\u0000\u0479\u047a"+ + "\u0003q/\u0000\u047a\u047b\u0001\u0000\u0000\u0000\u047b\u047c\u0006f"+ + "\u0016\u0000\u047c\u00e0\u0001\u0000\u0000\u0000\u047d\u047e\u0007\u0010"+ + "\u0000\u0000\u047e\u047f\u0007\u0003\u0000\u0000\u047f\u0480\u0007\u0005"+ + "\u0000\u0000\u0480\u0481\u0007\f\u0000\u0000\u0481\u0482\u0007\u0000\u0000"+ + "\u0000\u0482\u0483\u0007\f\u0000\u0000\u0483\u0484\u0007\u0005\u0000\u0000"+ + "\u0484\u0485\u0007\f\u0000\u0000\u0485\u00e2\u0001\u0000\u0000\u0000\u0486"+ + "\u048a\b \u0000\u0000\u0487\u0488\u0005/\u0000\u0000\u0488\u048a\b!\u0000"+ + "\u0000\u0489\u0486\u0001\u0000\u0000\u0000\u0489\u0487\u0001\u0000\u0000"+ + "\u0000\u048a\u00e4\u0001\u0000\u0000\u0000\u048b\u048d\u0003\u00e3h\u0000"+ + "\u048c\u048b\u0001\u0000\u0000\u0000\u048d\u048e\u0001\u0000\u0000\u0000"+ + "\u048e\u048c\u0001\u0000\u0000\u0000\u048e\u048f\u0001\u0000\u0000\u0000"+ + "\u048f\u00e6\u0001\u0000\u0000\u0000\u0490\u0491\u0003\u00e5i\u0000\u0491"+ + "\u0492\u0001\u0000\u0000\u0000\u0492\u0493\u0006j\u0017\u0000\u0493\u00e8"+ + "\u0001\u0000\u0000\u0000\u0494\u0495\u0003e)\u0000\u0495\u0496\u0001\u0000"+ + "\u0000\u0000\u0496\u0497\u0006k\u0018\u0000\u0497\u00ea\u0001\u0000\u0000"+ + "\u0000\u0498\u0499\u0003I\u001b\u0000\u0499\u049a\u0001\u0000\u0000\u0000"+ + "\u049a\u049b\u0006l\r\u0000\u049b\u00ec\u0001\u0000\u0000\u0000\u049c"+ + "\u049d\u0003K\u001c\u0000\u049d\u049e\u0001\u0000\u0000\u0000\u049e\u049f"+ + "\u0006m\r\u0000\u049f\u00ee\u0001\u0000\u0000\u0000\u04a0\u04a1\u0003"+ + "M\u001d\u0000\u04a1\u04a2\u0001\u0000\u0000\u0000\u04a2\u04a3\u0006n\r"+ + "\u0000\u04a3\u00f0\u0001\u0000\u0000\u0000\u04a4\u04a5\u0003O\u001e\u0000"+ + "\u04a5\u04a6\u0001\u0000\u0000\u0000\u04a6\u04a7\u0006o\u0012\u0000\u04a7"+ + "\u04a8\u0006o\u000e\u0000\u04a8\u00f2\u0001\u0000\u0000\u0000\u04a9\u04aa"+ + "\u0003{4\u0000\u04aa\u04ab\u0001\u0000\u0000\u0000\u04ab\u04ac\u0006p"+ + "\u0019\u0000\u04ac\u00f4\u0001\u0000\u0000\u0000\u04ad\u04ae\u0003w2\u0000"+ + "\u04ae\u04af\u0001\u0000\u0000\u0000\u04af\u04b0\u0006q\u0015\u0000\u04b0"+ + "\u00f6\u0001\u0000\u0000\u0000\u04b1\u04b2\u0003\u0091?\u0000\u04b2\u04b3"+ + "\u0001\u0000\u0000\u0000\u04b3\u04b4\u0006r\u001a\u0000\u04b4\u00f8\u0001"+ + "\u0000\u0000\u0000\u04b5\u04b6\u0003\u00b5Q\u0000\u04b6\u04b7\u0001\u0000"+ + "\u0000\u0000\u04b7\u04b8\u0006s\u001b\u0000\u04b8\u00fa\u0001\u0000\u0000"+ + "\u0000\u04b9\u04be\u0003S \u0000\u04ba\u04be\u0003Q\u001f\u0000\u04bb"+ + "\u04be\u0003a\'\u0000\u04bc\u04be\u0003\u00a9K\u0000\u04bd\u04b9\u0001"+ + "\u0000\u0000\u0000\u04bd\u04ba\u0001\u0000\u0000\u0000\u04bd\u04bb\u0001"+ + "\u0000\u0000\u0000\u04bd\u04bc\u0001\u0000\u0000\u0000\u04be\u00fc\u0001"+ + "\u0000\u0000\u0000\u04bf\u04c2\u0003S \u0000\u04c0\u04c2\u0003\u00a9K"+ + "\u0000\u04c1\u04bf\u0001\u0000\u0000\u0000\u04c1\u04c0\u0001\u0000\u0000"+ + "\u0000\u04c2\u04c6\u0001\u0000\u0000\u0000\u04c3\u04c5\u0003\u00fbt\u0000"+ + "\u04c4\u04c3\u0001\u0000\u0000\u0000\u04c5\u04c8\u0001\u0000\u0000\u0000"+ + "\u04c6\u04c4\u0001\u0000\u0000\u0000\u04c6\u04c7\u0001\u0000\u0000\u0000"+ + "\u04c7\u04d3\u0001\u0000\u0000\u0000\u04c8\u04c6\u0001\u0000\u0000\u0000"+ + "\u04c9\u04cc\u0003a\'\u0000\u04ca\u04cc\u0003[$\u0000\u04cb\u04c9\u0001"+ + "\u0000\u0000\u0000\u04cb\u04ca\u0001\u0000\u0000\u0000\u04cc\u04ce\u0001"+ + "\u0000\u0000\u0000\u04cd\u04cf\u0003\u00fbt\u0000\u04ce\u04cd\u0001\u0000"+ + "\u0000\u0000\u04cf\u04d0\u0001\u0000\u0000\u0000\u04d0\u04ce\u0001\u0000"+ + "\u0000\u0000\u04d0\u04d1\u0001\u0000\u0000\u0000\u04d1\u04d3\u0001\u0000"+ + "\u0000\u0000\u04d2\u04c1\u0001\u0000\u0000\u0000\u04d2\u04cb\u0001\u0000"+ + "\u0000\u0000\u04d3\u00fe\u0001\u0000\u0000\u0000\u04d4\u04d7\u0003\u00fd"+ + "u\u0000\u04d5\u04d7\u0003\u00c1W\u0000\u04d6\u04d4\u0001\u0000\u0000\u0000"+ + "\u04d6\u04d5\u0001\u0000\u0000\u0000\u04d7\u04d8\u0001\u0000\u0000\u0000"+ + "\u04d8\u04d6\u0001\u0000\u0000\u0000\u04d8\u04d9\u0001\u0000\u0000\u0000"+ + "\u04d9\u0100\u0001\u0000\u0000\u0000\u04da\u04db\u0003I\u001b\u0000\u04db"+ + "\u04dc\u0001\u0000\u0000\u0000\u04dc\u04dd\u0006w\r\u0000\u04dd\u0102"+ + "\u0001\u0000\u0000\u0000\u04de\u04df\u0003K\u001c\u0000\u04df\u04e0\u0001"+ + "\u0000\u0000\u0000\u04e0\u04e1\u0006x\r\u0000\u04e1\u0104\u0001\u0000"+ + "\u0000\u0000\u04e2\u04e3\u0003M\u001d\u0000\u04e3\u04e4\u0001\u0000\u0000"+ + "\u0000\u04e4\u04e5\u0006y\r\u0000\u04e5\u0106\u0001\u0000\u0000\u0000"+ + "\u04e6\u04e7\u0003O\u001e\u0000\u04e7\u04e8\u0001\u0000\u0000\u0000\u04e8"+ + "\u04e9\u0006z\u0012\u0000\u04e9\u04ea\u0006z\u000e\u0000\u04ea\u0108\u0001"+ + "\u0000\u0000\u0000\u04eb\u04ec\u0003q/\u0000\u04ec\u04ed\u0001\u0000\u0000"+ + "\u0000\u04ed\u04ee\u0006{\u0016\u0000\u04ee\u010a\u0001\u0000\u0000\u0000"+ + "\u04ef\u04f0\u0003w2\u0000\u04f0\u04f1\u0001\u0000\u0000\u0000\u04f1\u04f2"+ + "\u0006|\u0015\u0000\u04f2\u010c\u0001\u0000\u0000\u0000\u04f3\u04f4\u0003"+ + "{4\u0000\u04f4\u04f5\u0001\u0000\u0000\u0000\u04f5\u04f6\u0006}\u0019"+ + "\u0000\u04f6\u010e\u0001\u0000\u0000\u0000\u04f7\u04f8\u0003\u0091?\u0000"+ + "\u04f8\u04f9\u0001\u0000\u0000\u0000\u04f9\u04fa\u0006~\u001a\u0000\u04fa"+ + "\u0110\u0001\u0000\u0000\u0000\u04fb\u04fc\u0003\u00b5Q\u0000\u04fc\u04fd"+ + "\u0001\u0000\u0000\u0000\u04fd\u04fe\u0006\u007f\u001b\u0000\u04fe\u0112"+ + "\u0001\u0000\u0000\u0000\u04ff\u0500\u0007\f\u0000\u0000\u0500\u0501\u0007"+ + "\u0002\u0000\u0000\u0501\u0114\u0001\u0000\u0000\u0000\u0502\u0503\u0003"+ + "\u00ffv\u0000\u0503\u0504\u0001\u0000\u0000\u0000\u0504\u0505\u0006\u0081"+ + "\u001c\u0000\u0505\u0116\u0001\u0000\u0000\u0000\u0506\u0507\u0003I\u001b"+ + "\u0000\u0507\u0508\u0001\u0000\u0000\u0000\u0508\u0509\u0006\u0082\r\u0000"+ + "\u0509\u0118\u0001\u0000\u0000\u0000\u050a\u050b\u0003K\u001c\u0000\u050b"+ + "\u050c\u0001\u0000\u0000\u0000\u050c\u050d\u0006\u0083\r\u0000\u050d\u011a"+ + "\u0001\u0000\u0000\u0000\u050e\u050f\u0003M\u001d\u0000\u050f\u0510\u0001"+ + "\u0000\u0000\u0000\u0510\u0511\u0006\u0084\r\u0000\u0511\u011c\u0001\u0000"+ + "\u0000\u0000\u0512\u0513\u0003O\u001e\u0000\u0513\u0514\u0001\u0000\u0000"+ + "\u0000\u0514\u0515\u0006\u0085\u0012\u0000\u0515\u0516\u0006\u0085\u000e"+ + "\u0000\u0516\u011e\u0001\u0000\u0000\u0000\u0517\u0518\u0003\u00b7R\u0000"+ + "\u0518\u0519\u0001\u0000\u0000\u0000\u0519\u051a\u0006\u0086\u0010\u0000"+ + "\u051a\u051b\u0006\u0086\u001d\u0000\u051b\u0120\u0001\u0000\u0000\u0000"+ + "\u051c\u051d\u0007\u0007\u0000\u0000\u051d\u051e\u0007\t\u0000\u0000\u051e"+ + "\u051f\u0001\u0000\u0000\u0000\u051f\u0520\u0006\u0087\u001e\u0000\u0520"+ + "\u0122\u0001\u0000\u0000\u0000\u0521\u0522\u0007\u0013\u0000\u0000\u0522"+ + "\u0523\u0007\u0001\u0000\u0000\u0523\u0524\u0007\u0005\u0000\u0000\u0524"+ + "\u0525\u0007\n\u0000\u0000\u0525\u0526\u0001\u0000\u0000\u0000\u0526\u0527"+ + "\u0006\u0088\u001e\u0000\u0527\u0124\u0001\u0000\u0000\u0000\u0528\u0529"+ + "\b\"\u0000\u0000\u0529\u0126\u0001\u0000\u0000\u0000\u052a\u052c\u0003"+ + "\u0125\u0089\u0000\u052b\u052a\u0001\u0000\u0000\u0000\u052c\u052d\u0001"+ + "\u0000\u0000\u0000\u052d\u052b\u0001\u0000\u0000\u0000\u052d\u052e\u0001"+ + "\u0000\u0000\u0000\u052e\u052f\u0001\u0000\u0000\u0000\u052f\u0530\u0003"+ + "u1\u0000\u0530\u0532\u0001\u0000\u0000\u0000\u0531\u052b\u0001\u0000\u0000"+ + "\u0000\u0531\u0532\u0001\u0000\u0000\u0000\u0532\u0534\u0001\u0000\u0000"+ + "\u0000\u0533\u0535\u0003\u0125\u0089\u0000\u0534\u0533\u0001\u0000\u0000"+ + "\u0000\u0535\u0536\u0001\u0000\u0000\u0000\u0536\u0534\u0001\u0000\u0000"+ + "\u0000\u0536\u0537\u0001\u0000\u0000\u0000\u0537\u0128\u0001\u0000\u0000"+ + "\u0000\u0538\u0539\u0003\u0127\u008a\u0000\u0539\u053a\u0001\u0000\u0000"+ + "\u0000\u053a\u053b\u0006\u008b\u001f\u0000\u053b\u012a\u0001\u0000\u0000"+ + "\u0000\u053c\u053d\u0003I\u001b\u0000\u053d\u053e\u0001\u0000\u0000\u0000"+ + "\u053e\u053f\u0006\u008c\r\u0000\u053f\u012c\u0001\u0000\u0000\u0000\u0540"+ + "\u0541\u0003K\u001c\u0000\u0541\u0542\u0001\u0000\u0000\u0000\u0542\u0543"+ + "\u0006\u008d\r\u0000\u0543\u012e\u0001\u0000\u0000\u0000\u0544\u0545\u0003"+ + "M\u001d\u0000\u0545\u0546\u0001\u0000\u0000\u0000\u0546\u0547\u0006\u008e"+ + "\r\u0000\u0547\u0130\u0001\u0000\u0000\u0000\u0548\u0549\u0003O\u001e"+ + "\u0000\u0549\u054a\u0001\u0000\u0000\u0000\u054a\u054b\u0006\u008f\u0012"+ + "\u0000\u054b\u054c\u0006\u008f\u000e\u0000\u054c\u054d\u0006\u008f\u000e"+ + "\u0000\u054d\u0132\u0001\u0000\u0000\u0000\u054e\u054f\u0003q/\u0000\u054f"+ + "\u0550\u0001\u0000\u0000\u0000\u0550\u0551\u0006\u0090\u0016\u0000\u0551"+ + "\u0134\u0001\u0000\u0000\u0000\u0552\u0553\u0003w2\u0000\u0553\u0554\u0001"+ + "\u0000\u0000\u0000\u0554\u0555\u0006\u0091\u0015\u0000\u0555\u0136\u0001"+ + "\u0000\u0000\u0000\u0556\u0557\u0003{4\u0000\u0557\u0558\u0001\u0000\u0000"+ + "\u0000\u0558\u0559\u0006\u0092\u0019\u0000\u0559\u0138\u0001\u0000\u0000"+ + "\u0000\u055a\u055b\u0003\u0123\u0088\u0000\u055b\u055c\u0001\u0000\u0000"+ + "\u0000\u055c\u055d\u0006\u0093 \u0000\u055d\u013a\u0001\u0000\u0000\u0000"+ + "\u055e\u055f\u0003\u00ffv\u0000\u055f\u0560\u0001\u0000\u0000\u0000\u0560"+ + "\u0561\u0006\u0094\u001c\u0000\u0561\u013c\u0001\u0000\u0000\u0000\u0562"+ + "\u0563\u0003\u00c3X\u0000\u0563\u0564\u0001\u0000\u0000\u0000\u0564\u0565"+ + "\u0006\u0095!\u0000\u0565\u013e\u0001\u0000\u0000\u0000\u0566\u0567\u0003"+ + "\u0091?\u0000\u0567\u0568\u0001\u0000\u0000\u0000\u0568\u0569\u0006\u0096"+ + "\u001a\u0000\u0569\u0140\u0001\u0000\u0000\u0000\u056a\u056b\u0003\u00b5"+ + "Q\u0000\u056b\u056c\u0001\u0000\u0000\u0000\u056c\u056d\u0006\u0097\u001b"+ + "\u0000\u056d\u0142\u0001\u0000\u0000\u0000\u056e\u056f\u0003I\u001b\u0000"+ + "\u056f\u0570\u0001\u0000\u0000\u0000\u0570\u0571\u0006\u0098\r\u0000\u0571"+ + "\u0144\u0001\u0000\u0000\u0000\u0572\u0573\u0003K\u001c\u0000\u0573\u0574"+ + "\u0001\u0000\u0000\u0000\u0574\u0575\u0006\u0099\r\u0000\u0575\u0146\u0001"+ + "\u0000\u0000\u0000\u0576\u0577\u0003M\u001d\u0000\u0577\u0578\u0001\u0000"+ + "\u0000\u0000\u0578\u0579\u0006\u009a\r\u0000\u0579\u0148\u0001\u0000\u0000"+ + "\u0000\u057a\u057b\u0003O\u001e\u0000\u057b\u057c\u0001\u0000\u0000\u0000"+ + "\u057c\u057d\u0006\u009b\u0012\u0000\u057d\u057e\u0006\u009b\u000e\u0000"+ + "\u057e\u014a\u0001\u0000\u0000\u0000\u057f\u0580\u0003{4\u0000\u0580\u0581"+ + "\u0001\u0000\u0000\u0000\u0581\u0582\u0006\u009c\u0019\u0000\u0582\u014c"+ + "\u0001\u0000\u0000\u0000\u0583\u0584\u0003\u0091?\u0000\u0584\u0585\u0001"+ + "\u0000\u0000\u0000\u0585\u0586\u0006\u009d\u001a\u0000\u0586\u014e\u0001"+ + "\u0000\u0000\u0000\u0587\u0588\u0003\u00b5Q\u0000\u0588\u0589\u0001\u0000"+ + "\u0000\u0000\u0589\u058a\u0006\u009e\u001b\u0000\u058a\u0150\u0001\u0000"+ + "\u0000\u0000\u058b\u058c\u0003\u00c3X\u0000\u058c\u058d\u0001\u0000\u0000"+ + "\u0000\u058d\u058e\u0006\u009f!\u0000\u058e\u0152\u0001\u0000\u0000\u0000"+ + "\u058f\u0590\u0003\u00bfV\u0000\u0590\u0591\u0001\u0000\u0000\u0000\u0591"+ + "\u0592\u0006\u00a0\"\u0000\u0592\u0154\u0001\u0000\u0000\u0000\u0593\u0594"+ + "\u0003I\u001b\u0000\u0594\u0595\u0001\u0000\u0000\u0000\u0595\u0596\u0006"+ + "\u00a1\r\u0000\u0596\u0156\u0001\u0000\u0000\u0000\u0597\u0598\u0003K"+ + "\u001c\u0000\u0598\u0599\u0001\u0000\u0000\u0000\u0599\u059a\u0006\u00a2"+ + "\r\u0000\u059a\u0158\u0001\u0000\u0000\u0000\u059b\u059c\u0003M\u001d"+ + "\u0000\u059c\u059d\u0001\u0000\u0000\u0000\u059d\u059e\u0006\u00a3\r\u0000"+ + "\u059e\u015a\u0001\u0000\u0000\u0000\u059f\u05a0\u0003O\u001e\u0000\u05a0"+ + "\u05a1\u0001\u0000\u0000\u0000\u05a1\u05a2\u0006\u00a4\u0012\u0000\u05a2"+ + "\u05a3\u0006\u00a4\u000e\u0000\u05a3\u015c\u0001\u0000\u0000\u0000\u05a4"+ + "\u05a5\u0007\u0001\u0000\u0000\u05a5\u05a6\u0007\t\u0000\u0000\u05a6\u05a7"+ + "\u0007\u000f\u0000\u0000\u05a7\u05a8\u0007\u0007\u0000\u0000\u05a8\u015e"+ + "\u0001\u0000\u0000\u0000\u05a9\u05aa\u0003I\u001b\u0000\u05aa\u05ab\u0001"+ + "\u0000\u0000\u0000\u05ab\u05ac\u0006\u00a6\r\u0000\u05ac\u0160\u0001\u0000"+ + "\u0000\u0000\u05ad\u05ae\u0003K\u001c\u0000\u05ae\u05af\u0001\u0000\u0000"+ + "\u0000\u05af\u05b0\u0006\u00a7\r\u0000\u05b0\u0162\u0001\u0000\u0000\u0000"+ + "\u05b1\u05b2\u0003M\u001d\u0000\u05b2\u05b3\u0001\u0000\u0000\u0000\u05b3"+ + "\u05b4\u0006\u00a8\r\u0000\u05b4\u0164\u0001\u0000\u0000\u0000\u05b5\u05b6"+ + "\u0003\u00b9S\u0000\u05b6\u05b7\u0001\u0000\u0000\u0000\u05b7\u05b8\u0006"+ + "\u00a9\u0013\u0000\u05b8\u05b9\u0006\u00a9\u000e\u0000\u05b9\u0166\u0001"+ + "\u0000\u0000\u0000\u05ba\u05bb\u0003u1\u0000\u05bb\u05bc\u0001\u0000\u0000"+ + "\u0000\u05bc\u05bd\u0006\u00aa\u0014\u0000\u05bd\u0168\u0001\u0000\u0000"+ + "\u0000\u05be\u05c4\u0003[$\u0000\u05bf\u05c4\u0003Q\u001f\u0000\u05c0"+ + "\u05c4\u0003{4\u0000\u05c1\u05c4\u0003S \u0000\u05c2\u05c4\u0003a\'\u0000"+ + "\u05c3\u05be\u0001\u0000\u0000\u0000\u05c3\u05bf\u0001\u0000\u0000\u0000"+ + "\u05c3\u05c0\u0001\u0000\u0000\u0000\u05c3\u05c1\u0001\u0000\u0000\u0000"+ + "\u05c3\u05c2\u0001\u0000\u0000\u0000\u05c4\u05c5\u0001\u0000\u0000\u0000"+ + "\u05c5\u05c3\u0001\u0000\u0000\u0000\u05c5\u05c6\u0001\u0000\u0000\u0000"+ + "\u05c6\u016a\u0001\u0000\u0000\u0000\u05c7\u05c8\u0003I\u001b\u0000\u05c8"+ + "\u05c9\u0001\u0000\u0000\u0000\u05c9\u05ca\u0006\u00ac\r\u0000\u05ca\u016c"+ + "\u0001\u0000\u0000\u0000\u05cb\u05cc\u0003K\u001c\u0000\u05cc\u05cd\u0001"+ + "\u0000\u0000\u0000\u05cd\u05ce\u0006\u00ad\r\u0000\u05ce\u016e\u0001\u0000"+ + "\u0000\u0000\u05cf\u05d0\u0003M\u001d\u0000\u05d0\u05d1\u0001\u0000\u0000"+ + "\u0000\u05d1\u05d2\u0006\u00ae\r\u0000\u05d2\u0170\u0001\u0000\u0000\u0000"+ + "\u05d3\u05d4\u0003O\u001e\u0000\u05d4\u05d5\u0001\u0000\u0000\u0000\u05d5"+ + "\u05d6\u0006\u00af\u0012\u0000\u05d6\u05d7\u0006\u00af\u000e\u0000\u05d7"+ + "\u0172\u0001\u0000\u0000\u0000\u05d8\u05d9\u0003u1\u0000\u05d9\u05da\u0001"+ + "\u0000\u0000\u0000\u05da\u05db\u0006\u00b0\u0014\u0000\u05db\u0174\u0001"+ + "\u0000\u0000\u0000\u05dc\u05dd\u0003w2\u0000\u05dd\u05de\u0001\u0000\u0000"+ + "\u0000\u05de\u05df\u0006\u00b1\u0015\u0000\u05df\u0176\u0001\u0000\u0000"+ + "\u0000\u05e0\u05e1\u0003{4\u0000\u05e1\u05e2\u0001\u0000\u0000\u0000\u05e2"+ + "\u05e3\u0006\u00b2\u0019\u0000\u05e3\u0178\u0001\u0000\u0000\u0000\u05e4"+ + "\u05e5\u0003\u0121\u0087\u0000\u05e5\u05e6\u0001\u0000\u0000\u0000\u05e6"+ + "\u05e7\u0006\u00b3#\u0000\u05e7\u05e8\u0006\u00b3$\u0000\u05e8\u017a\u0001"+ + "\u0000\u0000\u0000\u05e9\u05ea\u0003\u00e5i\u0000\u05ea\u05eb\u0001\u0000"+ + "\u0000\u0000\u05eb\u05ec\u0006\u00b4\u0017\u0000\u05ec\u017c\u0001\u0000"+ + "\u0000\u0000\u05ed\u05ee\u0003e)\u0000\u05ee\u05ef\u0001\u0000\u0000\u0000"+ + "\u05ef\u05f0\u0006\u00b5\u0018\u0000\u05f0\u017e\u0001\u0000\u0000\u0000"+ + "\u05f1\u05f2\u0003I\u001b\u0000\u05f2\u05f3\u0001\u0000\u0000\u0000\u05f3"+ + "\u05f4\u0006\u00b6\r\u0000\u05f4\u0180\u0001\u0000\u0000\u0000\u05f5\u05f6"+ + "\u0003K\u001c\u0000\u05f6\u05f7\u0001\u0000\u0000\u0000\u05f7\u05f8\u0006"+ + "\u00b7\r\u0000\u05f8\u0182\u0001\u0000\u0000\u0000\u05f9\u05fa\u0003M"+ + "\u001d\u0000\u05fa\u05fb\u0001\u0000\u0000\u0000\u05fb\u05fc\u0006\u00b8"+ + "\r\u0000\u05fc\u0184\u0001\u0000\u0000\u0000\u05fd\u05fe\u0003O\u001e"+ + "\u0000\u05fe\u05ff\u0001\u0000\u0000\u0000\u05ff\u0600\u0006\u00b9\u0012"+ + "\u0000\u0600\u0601\u0006\u00b9\u000e\u0000\u0601\u0602\u0006\u00b9\u000e"+ + "\u0000\u0602\u0186\u0001\u0000\u0000\u0000\u0603\u0604\u0003w2\u0000\u0604"+ + "\u0605\u0001\u0000\u0000\u0000\u0605\u0606\u0006\u00ba\u0015\u0000\u0606"+ + "\u0188\u0001\u0000\u0000\u0000\u0607\u0608\u0003{4\u0000\u0608\u0609\u0001"+ + "\u0000\u0000\u0000\u0609\u060a\u0006\u00bb\u0019\u0000\u060a\u018a\u0001"+ + "\u0000\u0000\u0000\u060b\u060c\u0003\u00ffv\u0000\u060c\u060d\u0001\u0000"+ + "\u0000\u0000\u060d\u060e\u0006\u00bc\u001c\u0000\u060e\u018c\u0001\u0000"+ + "\u0000\u0000\u060f\u0610\u0003I\u001b\u0000\u0610\u0611\u0001\u0000\u0000"+ + "\u0000\u0611\u0612\u0006\u00bd\r\u0000\u0612\u018e\u0001\u0000\u0000\u0000"+ + "\u0613\u0614\u0003K\u001c\u0000\u0614\u0615\u0001\u0000\u0000\u0000\u0615"+ + "\u0616\u0006\u00be\r\u0000\u0616\u0190\u0001\u0000\u0000\u0000\u0617\u0618"+ + "\u0003M\u001d\u0000\u0618\u0619\u0001\u0000\u0000\u0000\u0619\u061a\u0006"+ + "\u00bf\r\u0000\u061a\u0192\u0001\u0000\u0000\u0000\u061b\u061c\u0003O"+ + "\u001e\u0000\u061c\u061d\u0001\u0000\u0000\u0000\u061d\u061e\u0006\u00c0"+ + "\u0012\u0000\u061e\u061f\u0006\u00c0\u000e\u0000\u061f\u0194\u0001\u0000"+ + "\u0000\u0000\u0620\u0621\u0007#\u0000\u0000\u0621\u0622\u0007\u0007\u0000"+ + "\u0000\u0622\u0623\u0007\u0001\u0000\u0000\u0623\u0624\u0007\t\u0000\u0000"+ + "\u0624\u0196\u0001\u0000\u0000\u0000\u0625\u0626\u0003\u0113\u0080\u0000"+ + "\u0626\u0627\u0001\u0000\u0000\u0000\u0627\u0628\u0006\u00c2%\u0000\u0628"+ + "\u0198\u0001\u0000\u0000\u0000\u0629\u062a\u0003\u0121\u0087\u0000\u062a"+ + "\u062b\u0001\u0000\u0000\u0000\u062b\u062c\u0006\u00c3#\u0000\u062c\u062d"+ + "\u0006\u00c3\u000e\u0000\u062d\u062e\u0006\u00c3\u0000\u0000\u062e\u019a"+ + "\u0001\u0000\u0000\u0000\u062f\u0630\u0007\u0014\u0000\u0000\u0630\u0631"+ + "\u0007\u0002\u0000\u0000\u0631\u0632\u0007\u0001\u0000\u0000\u0632\u0633"+ + "\u0007\t\u0000\u0000\u0633\u0634\u0007\u0011\u0000\u0000\u0634\u0635\u0001"+ + "\u0000\u0000\u0000\u0635\u0636\u0006\u00c4\u000e\u0000\u0636\u0637\u0006"+ + "\u00c4\u0000\u0000\u0637\u019c\u0001\u0000\u0000\u0000\u0638\u0639\u0003"+ + "\u00e5i\u0000\u0639\u063a\u0001\u0000\u0000\u0000\u063a\u063b\u0006\u00c5"+ + "\u0017\u0000\u063b\u019e\u0001\u0000\u0000\u0000\u063c\u063d\u0003e)\u0000"+ + "\u063d\u063e\u0001\u0000\u0000\u0000\u063e\u063f\u0006\u00c6\u0018\u0000"+ + "\u063f\u01a0\u0001\u0000\u0000\u0000\u0640\u0641\u0003u1\u0000\u0641\u0642"+ + "\u0001\u0000\u0000\u0000\u0642\u0643\u0006\u00c7\u0014\u0000\u0643\u01a2"+ + "\u0001\u0000\u0000\u0000\u0644\u0645\u0003\u00bfV\u0000\u0645\u0646\u0001"+ + "\u0000\u0000\u0000\u0646\u0647\u0006\u00c8\"\u0000\u0647\u01a4\u0001\u0000"+ + "\u0000\u0000\u0648\u0649\u0003\u00c3X\u0000\u0649\u064a\u0001\u0000\u0000"+ + "\u0000\u064a\u064b\u0006\u00c9!\u0000\u064b\u01a6\u0001\u0000\u0000\u0000"+ + "\u064c\u064d\u0003I\u001b\u0000\u064d\u064e\u0001\u0000\u0000\u0000\u064e"+ + "\u064f\u0006\u00ca\r\u0000\u064f\u01a8\u0001\u0000\u0000\u0000\u0650\u0651"+ + "\u0003K\u001c\u0000\u0651\u0652\u0001\u0000\u0000\u0000\u0652\u0653\u0006"+ + "\u00cb\r\u0000\u0653\u01aa\u0001\u0000\u0000\u0000\u0654\u0655\u0003M"+ + "\u001d\u0000\u0655\u0656\u0001\u0000\u0000\u0000\u0656\u0657\u0006\u00cc"+ + "\r\u0000\u0657\u01ac\u0001\u0000\u0000\u0000\u0658\u0659\u0003O\u001e"+ + "\u0000\u0659\u065a\u0001\u0000\u0000\u0000\u065a\u065b\u0006\u00cd\u0012"+ + "\u0000\u065b\u065c\u0006\u00cd\u000e\u0000\u065c\u01ae\u0001\u0000\u0000"+ + "\u0000\u065d\u065e\u0003\u00e5i\u0000\u065e\u065f\u0001\u0000\u0000\u0000"+ + "\u065f\u0660\u0006\u00ce\u0017\u0000\u0660\u0661\u0006\u00ce\u000e\u0000"+ + "\u0661\u0662\u0006\u00ce&\u0000\u0662\u01b0\u0001\u0000\u0000\u0000\u0663"+ + "\u0664\u0003e)\u0000\u0664\u0665\u0001\u0000\u0000\u0000\u0665\u0666\u0006"+ + "\u00cf\u0018\u0000\u0666\u0667\u0006\u00cf\u000e\u0000\u0667\u0668\u0006"+ + "\u00cf&\u0000\u0668\u01b2\u0001\u0000\u0000\u0000\u0669\u066a\u0003I\u001b"+ + "\u0000\u066a\u066b\u0001\u0000\u0000\u0000\u066b\u066c\u0006\u00d0\r\u0000"+ + "\u066c\u01b4\u0001\u0000\u0000\u0000\u066d\u066e\u0003K\u001c\u0000\u066e"+ + "\u066f\u0001\u0000\u0000\u0000\u066f\u0670\u0006\u00d1\r\u0000\u0670\u01b6"+ + "\u0001\u0000\u0000\u0000\u0671\u0672\u0003M\u001d\u0000\u0672\u0673\u0001"+ + "\u0000\u0000\u0000\u0673\u0674\u0006\u00d2\r\u0000\u0674\u01b8\u0001\u0000"+ + "\u0000\u0000\u0675\u0676\u0003u1\u0000\u0676\u0677\u0001\u0000\u0000\u0000"+ + "\u0677\u0678\u0006\u00d3\u0014\u0000\u0678\u0679\u0006\u00d3\u000e\u0000"+ + "\u0679\u067a\u0006\u00d3\u000b\u0000\u067a\u01ba\u0001\u0000\u0000\u0000"+ + "\u067b\u067c\u0003w2\u0000\u067c\u067d\u0001\u0000\u0000\u0000\u067d\u067e"+ + "\u0006\u00d4\u0015\u0000\u067e\u067f\u0006\u00d4\u000e\u0000\u067f\u0680"+ + "\u0006\u00d4\u000b\u0000\u0680\u01bc\u0001\u0000\u0000\u0000\u0681\u0682"+ + "\u0003I\u001b\u0000\u0682\u0683\u0001\u0000\u0000\u0000\u0683\u0684\u0006"+ + "\u00d5\r\u0000\u0684\u01be\u0001\u0000\u0000\u0000\u0685\u0686\u0003K"+ + "\u001c\u0000\u0686\u0687\u0001\u0000\u0000\u0000\u0687\u0688\u0006\u00d6"+ + "\r\u0000\u0688\u01c0\u0001\u0000\u0000\u0000\u0689\u068a\u0003M\u001d"+ + "\u0000\u068a\u068b\u0001\u0000\u0000\u0000\u068b\u068c\u0006\u00d7\r\u0000"+ + "\u068c\u01c2\u0001\u0000\u0000\u0000\u068d\u068e\u0003\u00c3X\u0000\u068e"+ + "\u068f\u0001\u0000\u0000\u0000\u068f\u0690\u0006\u00d8\u000e\u0000\u0690"+ + "\u0691\u0006\u00d8\u0000\u0000\u0691\u0692\u0006\u00d8!\u0000\u0692\u01c4"+ + "\u0001\u0000\u0000\u0000\u0693\u0694\u0003\u00bfV\u0000\u0694\u0695\u0001"+ + "\u0000\u0000\u0000\u0695\u0696\u0006\u00d9\u000e\u0000\u0696\u0697\u0006"+ + "\u00d9\u0000\u0000\u0697\u0698\u0006\u00d9\"\u0000\u0698\u01c6\u0001\u0000"+ + "\u0000\u0000\u0699\u069a\u0003k,\u0000\u069a\u069b\u0001\u0000\u0000\u0000"+ + "\u069b\u069c\u0006\u00da\u000e\u0000\u069c\u069d\u0006\u00da\u0000\u0000"+ + "\u069d\u069e\u0006\u00da\'\u0000\u069e\u01c8\u0001\u0000\u0000\u0000\u069f"+ + "\u06a0\u0003O\u001e\u0000\u06a0\u06a1\u0001\u0000\u0000\u0000\u06a1\u06a2"+ + "\u0006\u00db\u0012\u0000\u06a2\u06a3\u0006\u00db\u000e\u0000\u06a3\u01ca"+ + "\u0001\u0000\u0000\u0000\u06a4\u06a5\u0003O\u001e\u0000\u06a5\u06a6\u0001"+ + "\u0000\u0000\u0000\u06a6\u06a7\u0006\u00dc\u0012\u0000\u06a7\u06a8\u0006"+ + "\u00dc\u000e\u0000\u06a8\u01cc\u0001\u0000\u0000\u0000\u06a9\u06aa\u0003"+ + "\u0121\u0087\u0000\u06aa\u06ab\u0001\u0000\u0000\u0000\u06ab\u06ac\u0006"+ + "\u00dd#\u0000\u06ac\u01ce\u0001\u0000\u0000\u0000\u06ad\u06ae\u0003\u0113"+ + "\u0080\u0000\u06ae\u06af\u0001\u0000\u0000\u0000\u06af\u06b0\u0006\u00de"+ + "%\u0000\u06b0\u01d0\u0001\u0000\u0000\u0000\u06b1\u06b2\u0003{4\u0000"+ + "\u06b2\u06b3\u0001\u0000\u0000\u0000\u06b3\u06b4\u0006\u00df\u0019\u0000"+ + "\u06b4\u01d2\u0001\u0000\u0000\u0000\u06b5\u06b6\u0003w2\u0000\u06b6\u06b7"+ + "\u0001\u0000\u0000\u0000\u06b7\u06b8\u0006\u00e0\u0015\u0000\u06b8\u01d4"+ + "\u0001\u0000\u0000\u0000\u06b9\u06ba\u0003\u00c3X\u0000\u06ba\u06bb\u0001"+ + "\u0000\u0000\u0000\u06bb\u06bc\u0006\u00e1!\u0000\u06bc\u01d6\u0001\u0000"+ + "\u0000\u0000\u06bd\u06be\u0003\u00bfV\u0000\u06be\u06bf\u0001\u0000\u0000"+ + "\u0000\u06bf\u06c0\u0006\u00e2\"\u0000\u06c0\u01d8\u0001\u0000\u0000\u0000"+ + "\u06c1\u06c2\u0003I\u001b\u0000\u06c2\u06c3\u0001\u0000\u0000\u0000\u06c3"+ + "\u06c4\u0006\u00e3\r\u0000\u06c4\u01da\u0001\u0000\u0000\u0000\u06c5\u06c6"+ + "\u0003K\u001c\u0000\u06c6\u06c7\u0001\u0000\u0000\u0000\u06c7\u06c8\u0006"+ + "\u00e4\r\u0000\u06c8\u01dc\u0001\u0000\u0000\u0000\u06c9\u06ca\u0003M"+ + "\u001d\u0000\u06ca\u06cb\u0001\u0000\u0000\u0000\u06cb\u06cc\u0006\u00e5"+ + "\r\u0000\u06cc\u01de\u0001\u0000\u0000\u0000\u06cd\u06ce\u0003O\u001e"+ + "\u0000\u06ce\u06cf\u0001\u0000\u0000\u0000\u06cf\u06d0\u0006\u00e6\u0012"+ + "\u0000\u06d0\u06d1\u0006\u00e6\u000e\u0000\u06d1\u01e0\u0001\u0000\u0000"+ + "\u0000\u06d2\u06d3\u0003\u00bfV\u0000\u06d3\u06d4\u0001\u0000\u0000\u0000"+ + "\u06d4\u06d5\u0006\u00e7\"\u0000\u06d5\u01e2\u0001\u0000\u0000\u0000\u06d6"+ + "\u06d7\u0003M\u001d\u0000\u06d7\u06d8\u0001\u0000\u0000\u0000\u06d8\u06d9"+ + "\u0006\u00e8\r\u0000\u06d9\u01e4\u0001\u0000\u0000\u0000\u06da\u06db\u0003"+ + "I\u001b\u0000\u06db\u06dc\u0001\u0000\u0000\u0000\u06dc\u06dd\u0006\u00e9"+ + "\r\u0000\u06dd\u01e6\u0001\u0000\u0000\u0000\u06de\u06df\u0003K\u001c"+ + "\u0000\u06df\u06e0\u0001\u0000\u0000\u0000\u06e0\u06e1\u0006\u00ea\r\u0000"+ + "\u06e1\u01e8\u0001\u0000\u0000\u0000\u06e2\u06e3\u0003\u00bbT\u0000\u06e3"+ + "\u06e4\u0001\u0000\u0000\u0000\u06e4\u06e5\u0006\u00eb(\u0000\u06e5\u06e6"+ + "\u0006\u00eb\u0011\u0000\u06e6\u01ea\u0001\u0000\u0000\u0000\u06e7\u06e8"+ + "\u0003O\u001e\u0000\u06e8\u06e9\u0001\u0000\u0000\u0000\u06e9\u06ea\u0006"+ + "\u00ec\u0012\u0000\u06ea\u06eb\u0006\u00ec\u000e\u0000\u06eb\u01ec\u0001"+ + "\u0000\u0000\u0000\u06ec\u06ed\u0003M\u001d\u0000\u06ed\u06ee\u0001\u0000"+ + "\u0000\u0000\u06ee\u06ef\u0006\u00ed\r\u0000\u06ef\u01ee\u0001\u0000\u0000"+ + "\u0000\u06f0\u06f1\u0003I\u001b\u0000\u06f1\u06f2\u0001\u0000\u0000\u0000"+ + "\u06f2\u06f3\u0006\u00ee\r\u0000\u06f3\u01f0\u0001\u0000\u0000\u0000\u06f4"+ + "\u06f5\u0003K\u001c\u0000\u06f5\u06f6\u0001\u0000\u0000\u0000\u06f6\u06f7"+ + "\u0006\u00ef\r\u0000\u06f7\u01f2\u0001\u0000\u0000\u0000E\u0000\u0001"+ + "\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010"+ + "\u0011\u0012\u02e3\u02ed\u02f1\u02f4\u02fd\u02ff\u030a\u031d\u0322\u032b"+ + "\u0332\u0337\u0339\u0344\u034c\u034f\u0351\u0356\u035b\u0361\u0368\u036d"+ + "\u0373\u0376\u037e\u0382\u0402\u0407\u040e\u0410\u042a\u042f\u0434\u0436"+ + "\u043c\u0489\u048e\u04bd\u04c1\u04c6\u04cb\u04d0\u04d2\u04d6\u04d8\u052d"+ + "\u0531\u0536\u05c3\u05c5)\u0005\u0001\u0000\u0005\u0004\u0000\u0005\u0006"+ + "\u0000\u0005\u0002\u0000\u0005\u0003\u0000\u0005\b\u0000\u0005\u0005\u0000"+ + "\u0005\t\u0000\u0005\r\u0000\u0005\u0010\u0000\u0005\u000b\u0000\u0005"+ + "\u000e\u0000\u0005\u0012\u0000\u0000\u0001\u0000\u0004\u0000\u0000\u0007"+ + "\u0010\u0000\u0007H\u0000\u0005\u0000\u0000\u0007\u001f\u0000\u0007I\u0000"+ + "\u0007(\u0000\u0007)\u0000\u0007&\u0000\u0007U\u0000\u0007 \u0000\u0007"+ + "+\u0000\u00076\u0000\u0007G\u0000\u0007Y\u0000\u0005\n\u0000\u0005\u0007"+ + "\u0000\u0007c\u0000\u0007b\u0000\u0007M\u0000\u0007L\u0000\u0007a\u0000"+ + "\u0005\f\u0000\u0007]\u0000\u0005\u000f\u0000\u0007#\u0000\u0007J\u0000"; public static final ATN _ATN = new ATNDeserializer().deserialize(_serializedATN.toCharArray()); static { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp index cfee76afb26b..c0b1e8c308d6 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.interp @@ -49,14 +49,12 @@ null 'is' 'last' 'like' -'(' 'not' 'null' 'nulls' 'or' '?' 'rlike' -')' 'true' '==' '=~' @@ -76,6 +74,8 @@ null null ']' null +')' +null null null null @@ -194,14 +194,12 @@ IN IS LAST LIKE -LP NOT NULL NULLS OR PARAM RLIKE -RP TRUE EQ CIEQ @@ -220,6 +218,8 @@ RIGHT_BRACES NAMED_OR_POSITIONAL_PARAM OPENING_BRACKET CLOSING_BRACKET +LP +RP UNQUOTED_IDENTIFIER QUOTED_IDENTIFIER EXPR_LINE_COMMENT @@ -365,4 +365,4 @@ forkSubQueryProcessingCommand atn: -[4, 1, 142, 706, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 156, 8, 1, 10, 1, 12, 1, 159, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 167, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 192, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 204, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 211, 8, 5, 10, 5, 12, 5, 214, 9, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 221, 8, 5, 1, 5, 1, 5, 1, 5, 3, 5, 226, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 234, 8, 5, 10, 5, 12, 5, 237, 9, 5, 1, 6, 1, 6, 3, 6, 241, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 248, 8, 6, 1, 6, 1, 6, 1, 6, 3, 6, 253, 8, 6, 1, 7, 1, 7, 1, 7, 3, 7, 258, 8, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 268, 8, 8, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 274, 8, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 5, 9, 282, 8, 9, 10, 9, 12, 9, 285, 9, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 295, 8, 10, 1, 10, 1, 10, 1, 10, 5, 10, 300, 8, 10, 10, 10, 12, 10, 303, 9, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 311, 8, 11, 10, 11, 12, 11, 314, 9, 11, 1, 11, 1, 11, 3, 11, 318, 8, 11, 3, 11, 320, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 330, 8, 13, 10, 13, 12, 13, 333, 9, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 5, 17, 349, 8, 17, 10, 17, 12, 17, 352, 9, 17, 1, 18, 1, 18, 1, 18, 3, 18, 357, 8, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 365, 8, 19, 10, 19, 12, 19, 368, 9, 19, 1, 19, 3, 19, 371, 8, 19, 1, 20, 1, 20, 1, 20, 3, 20, 376, 8, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 5, 23, 388, 8, 23, 10, 23, 12, 23, 391, 9, 23, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 397, 8, 24, 10, 24, 12, 24, 400, 9, 24, 1, 24, 3, 24, 403, 8, 24, 1, 24, 1, 24, 3, 24, 407, 8, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 3, 26, 414, 8, 26, 1, 26, 1, 26, 3, 26, 418, 8, 26, 1, 27, 1, 27, 1, 27, 5, 27, 423, 8, 27, 10, 27, 12, 27, 426, 9, 27, 1, 28, 1, 28, 1, 28, 3, 28, 431, 8, 28, 1, 29, 1, 29, 1, 29, 5, 29, 436, 8, 29, 10, 29, 12, 29, 439, 9, 29, 1, 30, 1, 30, 1, 30, 5, 30, 444, 8, 30, 10, 30, 12, 30, 447, 9, 30, 1, 31, 1, 31, 1, 31, 5, 31, 452, 8, 31, 10, 31, 12, 31, 455, 9, 31, 1, 32, 1, 32, 1, 33, 1, 33, 3, 33, 461, 8, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 476, 8, 34, 10, 34, 12, 34, 479, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 487, 8, 34, 10, 34, 12, 34, 490, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 498, 8, 34, 10, 34, 12, 34, 501, 9, 34, 1, 34, 1, 34, 3, 34, 505, 8, 34, 1, 35, 1, 35, 3, 35, 509, 8, 35, 1, 36, 1, 36, 3, 36, 513, 8, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 522, 8, 38, 10, 38, 12, 38, 525, 9, 38, 1, 39, 1, 39, 3, 39, 529, 8, 39, 1, 39, 1, 39, 3, 39, 533, 8, 39, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 5, 42, 545, 8, 42, 10, 42, 12, 42, 548, 9, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 3, 44, 558, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 5, 47, 570, 8, 47, 10, 47, 12, 47, 573, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 3, 50, 583, 8, 50, 1, 51, 3, 51, 586, 8, 51, 1, 51, 1, 51, 1, 52, 3, 52, 591, 8, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 613, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 5, 58, 619, 8, 58, 10, 58, 12, 58, 622, 9, 58, 3, 58, 624, 8, 58, 1, 59, 1, 59, 1, 59, 3, 59, 629, 8, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 3, 61, 642, 8, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 5, 64, 655, 8, 64, 10, 64, 12, 64, 658, 9, 64, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 666, 8, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 673, 8, 66, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 69, 4, 69, 682, 8, 69, 11, 69, 12, 69, 683, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 5, 71, 696, 8, 71, 10, 71, 12, 71, 699, 9, 71, 1, 72, 1, 72, 1, 72, 3, 72, 704, 8, 72, 1, 72, 0, 5, 2, 10, 18, 20, 142, 73, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 0, 9, 1, 0, 66, 67, 1, 0, 68, 70, 2, 0, 32, 32, 85, 85, 1, 0, 76, 77, 2, 0, 37, 37, 42, 42, 2, 0, 45, 45, 48, 48, 2, 0, 44, 44, 58, 58, 2, 0, 59, 59, 61, 65, 2, 0, 17, 17, 24, 25, 733, 0, 146, 1, 0, 0, 0, 2, 149, 1, 0, 0, 0, 4, 166, 1, 0, 0, 0, 6, 191, 1, 0, 0, 0, 8, 193, 1, 0, 0, 0, 10, 225, 1, 0, 0, 0, 12, 252, 1, 0, 0, 0, 14, 254, 1, 0, 0, 0, 16, 267, 1, 0, 0, 0, 18, 273, 1, 0, 0, 0, 20, 294, 1, 0, 0, 0, 22, 304, 1, 0, 0, 0, 24, 323, 1, 0, 0, 0, 26, 325, 1, 0, 0, 0, 28, 336, 1, 0, 0, 0, 30, 340, 1, 0, 0, 0, 32, 342, 1, 0, 0, 0, 34, 345, 1, 0, 0, 0, 36, 356, 1, 0, 0, 0, 38, 360, 1, 0, 0, 0, 40, 375, 1, 0, 0, 0, 42, 379, 1, 0, 0, 0, 44, 381, 1, 0, 0, 0, 46, 383, 1, 0, 0, 0, 48, 392, 1, 0, 0, 0, 50, 408, 1, 0, 0, 0, 52, 411, 1, 0, 0, 0, 54, 419, 1, 0, 0, 0, 56, 427, 1, 0, 0, 0, 58, 432, 1, 0, 0, 0, 60, 440, 1, 0, 0, 0, 62, 448, 1, 0, 0, 0, 64, 456, 1, 0, 0, 0, 66, 460, 1, 0, 0, 0, 68, 504, 1, 0, 0, 0, 70, 508, 1, 0, 0, 0, 72, 512, 1, 0, 0, 0, 74, 514, 1, 0, 0, 0, 76, 517, 1, 0, 0, 0, 78, 526, 1, 0, 0, 0, 80, 534, 1, 0, 0, 0, 82, 537, 1, 0, 0, 0, 84, 540, 1, 0, 0, 0, 86, 549, 1, 0, 0, 0, 88, 553, 1, 0, 0, 0, 90, 559, 1, 0, 0, 0, 92, 563, 1, 0, 0, 0, 94, 566, 1, 0, 0, 0, 96, 574, 1, 0, 0, 0, 98, 578, 1, 0, 0, 0, 100, 582, 1, 0, 0, 0, 102, 585, 1, 0, 0, 0, 104, 590, 1, 0, 0, 0, 106, 594, 1, 0, 0, 0, 108, 596, 1, 0, 0, 0, 110, 598, 1, 0, 0, 0, 112, 601, 1, 0, 0, 0, 114, 605, 1, 0, 0, 0, 116, 608, 1, 0, 0, 0, 118, 628, 1, 0, 0, 0, 120, 632, 1, 0, 0, 0, 122, 637, 1, 0, 0, 0, 124, 643, 1, 0, 0, 0, 126, 648, 1, 0, 0, 0, 128, 650, 1, 0, 0, 0, 130, 659, 1, 0, 0, 0, 132, 661, 1, 0, 0, 0, 134, 674, 1, 0, 0, 0, 136, 677, 1, 0, 0, 0, 138, 681, 1, 0, 0, 0, 140, 685, 1, 0, 0, 0, 142, 689, 1, 0, 0, 0, 144, 703, 1, 0, 0, 0, 146, 147, 3, 2, 1, 0, 147, 148, 5, 0, 0, 1, 148, 1, 1, 0, 0, 0, 149, 150, 6, 1, -1, 0, 150, 151, 3, 4, 2, 0, 151, 157, 1, 0, 0, 0, 152, 153, 10, 1, 0, 0, 153, 154, 5, 31, 0, 0, 154, 156, 3, 6, 3, 0, 155, 152, 1, 0, 0, 0, 156, 159, 1, 0, 0, 0, 157, 155, 1, 0, 0, 0, 157, 158, 1, 0, 0, 0, 158, 3, 1, 0, 0, 0, 159, 157, 1, 0, 0, 0, 160, 167, 3, 110, 55, 0, 161, 167, 3, 38, 19, 0, 162, 167, 3, 32, 16, 0, 163, 167, 3, 114, 57, 0, 164, 165, 4, 2, 1, 0, 165, 167, 3, 48, 24, 0, 166, 160, 1, 0, 0, 0, 166, 161, 1, 0, 0, 0, 166, 162, 1, 0, 0, 0, 166, 163, 1, 0, 0, 0, 166, 164, 1, 0, 0, 0, 167, 5, 1, 0, 0, 0, 168, 192, 3, 50, 25, 0, 169, 192, 3, 8, 4, 0, 170, 192, 3, 80, 40, 0, 171, 192, 3, 74, 37, 0, 172, 192, 3, 52, 26, 0, 173, 192, 3, 76, 38, 0, 174, 192, 3, 82, 41, 0, 175, 192, 3, 84, 42, 0, 176, 192, 3, 88, 44, 0, 177, 192, 3, 90, 45, 0, 178, 192, 3, 116, 58, 0, 179, 192, 3, 92, 46, 0, 180, 192, 3, 124, 62, 0, 181, 182, 4, 3, 2, 0, 182, 192, 3, 122, 61, 0, 183, 184, 4, 3, 3, 0, 184, 192, 3, 120, 60, 0, 185, 186, 4, 3, 4, 0, 186, 192, 3, 132, 66, 0, 187, 188, 4, 3, 5, 0, 188, 192, 3, 134, 67, 0, 189, 190, 4, 3, 6, 0, 190, 192, 3, 136, 68, 0, 191, 168, 1, 0, 0, 0, 191, 169, 1, 0, 0, 0, 191, 170, 1, 0, 0, 0, 191, 171, 1, 0, 0, 0, 191, 172, 1, 0, 0, 0, 191, 173, 1, 0, 0, 0, 191, 174, 1, 0, 0, 0, 191, 175, 1, 0, 0, 0, 191, 176, 1, 0, 0, 0, 191, 177, 1, 0, 0, 0, 191, 178, 1, 0, 0, 0, 191, 179, 1, 0, 0, 0, 191, 180, 1, 0, 0, 0, 191, 181, 1, 0, 0, 0, 191, 183, 1, 0, 0, 0, 191, 185, 1, 0, 0, 0, 191, 187, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 7, 1, 0, 0, 0, 193, 194, 5, 16, 0, 0, 194, 195, 3, 10, 5, 0, 195, 9, 1, 0, 0, 0, 196, 197, 6, 5, -1, 0, 197, 198, 5, 51, 0, 0, 198, 226, 3, 10, 5, 8, 199, 226, 3, 16, 8, 0, 200, 226, 3, 12, 6, 0, 201, 203, 3, 16, 8, 0, 202, 204, 5, 51, 0, 0, 203, 202, 1, 0, 0, 0, 203, 204, 1, 0, 0, 0, 204, 205, 1, 0, 0, 0, 205, 206, 5, 46, 0, 0, 206, 207, 5, 50, 0, 0, 207, 212, 3, 16, 8, 0, 208, 209, 5, 41, 0, 0, 209, 211, 3, 16, 8, 0, 210, 208, 1, 0, 0, 0, 211, 214, 1, 0, 0, 0, 212, 210, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 215, 1, 0, 0, 0, 214, 212, 1, 0, 0, 0, 215, 216, 5, 57, 0, 0, 216, 226, 1, 0, 0, 0, 217, 218, 3, 16, 8, 0, 218, 220, 5, 47, 0, 0, 219, 221, 5, 51, 0, 0, 220, 219, 1, 0, 0, 0, 220, 221, 1, 0, 0, 0, 221, 222, 1, 0, 0, 0, 222, 223, 5, 52, 0, 0, 223, 226, 1, 0, 0, 0, 224, 226, 3, 14, 7, 0, 225, 196, 1, 0, 0, 0, 225, 199, 1, 0, 0, 0, 225, 200, 1, 0, 0, 0, 225, 201, 1, 0, 0, 0, 225, 217, 1, 0, 0, 0, 225, 224, 1, 0, 0, 0, 226, 235, 1, 0, 0, 0, 227, 228, 10, 5, 0, 0, 228, 229, 5, 36, 0, 0, 229, 234, 3, 10, 5, 6, 230, 231, 10, 4, 0, 0, 231, 232, 5, 54, 0, 0, 232, 234, 3, 10, 5, 5, 233, 227, 1, 0, 0, 0, 233, 230, 1, 0, 0, 0, 234, 237, 1, 0, 0, 0, 235, 233, 1, 0, 0, 0, 235, 236, 1, 0, 0, 0, 236, 11, 1, 0, 0, 0, 237, 235, 1, 0, 0, 0, 238, 240, 3, 16, 8, 0, 239, 241, 5, 51, 0, 0, 240, 239, 1, 0, 0, 0, 240, 241, 1, 0, 0, 0, 241, 242, 1, 0, 0, 0, 242, 243, 5, 49, 0, 0, 243, 244, 3, 106, 53, 0, 244, 253, 1, 0, 0, 0, 245, 247, 3, 16, 8, 0, 246, 248, 5, 51, 0, 0, 247, 246, 1, 0, 0, 0, 247, 248, 1, 0, 0, 0, 248, 249, 1, 0, 0, 0, 249, 250, 5, 56, 0, 0, 250, 251, 3, 106, 53, 0, 251, 253, 1, 0, 0, 0, 252, 238, 1, 0, 0, 0, 252, 245, 1, 0, 0, 0, 253, 13, 1, 0, 0, 0, 254, 257, 3, 58, 29, 0, 255, 256, 5, 39, 0, 0, 256, 258, 3, 30, 15, 0, 257, 255, 1, 0, 0, 0, 257, 258, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 260, 5, 40, 0, 0, 260, 261, 3, 68, 34, 0, 261, 15, 1, 0, 0, 0, 262, 268, 3, 18, 9, 0, 263, 264, 3, 18, 9, 0, 264, 265, 3, 108, 54, 0, 265, 266, 3, 18, 9, 0, 266, 268, 1, 0, 0, 0, 267, 262, 1, 0, 0, 0, 267, 263, 1, 0, 0, 0, 268, 17, 1, 0, 0, 0, 269, 270, 6, 9, -1, 0, 270, 274, 3, 20, 10, 0, 271, 272, 7, 0, 0, 0, 272, 274, 3, 18, 9, 3, 273, 269, 1, 0, 0, 0, 273, 271, 1, 0, 0, 0, 274, 283, 1, 0, 0, 0, 275, 276, 10, 2, 0, 0, 276, 277, 7, 1, 0, 0, 277, 282, 3, 18, 9, 3, 278, 279, 10, 1, 0, 0, 279, 280, 7, 0, 0, 0, 280, 282, 3, 18, 9, 2, 281, 275, 1, 0, 0, 0, 281, 278, 1, 0, 0, 0, 282, 285, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 19, 1, 0, 0, 0, 285, 283, 1, 0, 0, 0, 286, 287, 6, 10, -1, 0, 287, 295, 3, 68, 34, 0, 288, 295, 3, 58, 29, 0, 289, 295, 3, 22, 11, 0, 290, 291, 5, 50, 0, 0, 291, 292, 3, 10, 5, 0, 292, 293, 5, 57, 0, 0, 293, 295, 1, 0, 0, 0, 294, 286, 1, 0, 0, 0, 294, 288, 1, 0, 0, 0, 294, 289, 1, 0, 0, 0, 294, 290, 1, 0, 0, 0, 295, 301, 1, 0, 0, 0, 296, 297, 10, 1, 0, 0, 297, 298, 5, 39, 0, 0, 298, 300, 3, 30, 15, 0, 299, 296, 1, 0, 0, 0, 300, 303, 1, 0, 0, 0, 301, 299, 1, 0, 0, 0, 301, 302, 1, 0, 0, 0, 302, 21, 1, 0, 0, 0, 303, 301, 1, 0, 0, 0, 304, 305, 3, 24, 12, 0, 305, 319, 5, 50, 0, 0, 306, 320, 5, 68, 0, 0, 307, 312, 3, 10, 5, 0, 308, 309, 5, 41, 0, 0, 309, 311, 3, 10, 5, 0, 310, 308, 1, 0, 0, 0, 311, 314, 1, 0, 0, 0, 312, 310, 1, 0, 0, 0, 312, 313, 1, 0, 0, 0, 313, 317, 1, 0, 0, 0, 314, 312, 1, 0, 0, 0, 315, 316, 5, 41, 0, 0, 316, 318, 3, 26, 13, 0, 317, 315, 1, 0, 0, 0, 317, 318, 1, 0, 0, 0, 318, 320, 1, 0, 0, 0, 319, 306, 1, 0, 0, 0, 319, 307, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 321, 1, 0, 0, 0, 321, 322, 5, 57, 0, 0, 322, 23, 1, 0, 0, 0, 323, 324, 3, 72, 36, 0, 324, 25, 1, 0, 0, 0, 325, 326, 5, 71, 0, 0, 326, 331, 3, 28, 14, 0, 327, 328, 5, 41, 0, 0, 328, 330, 3, 28, 14, 0, 329, 327, 1, 0, 0, 0, 330, 333, 1, 0, 0, 0, 331, 329, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 334, 1, 0, 0, 0, 333, 331, 1, 0, 0, 0, 334, 335, 5, 72, 0, 0, 335, 27, 1, 0, 0, 0, 336, 337, 3, 106, 53, 0, 337, 338, 5, 40, 0, 0, 338, 339, 3, 68, 34, 0, 339, 29, 1, 0, 0, 0, 340, 341, 3, 64, 32, 0, 341, 31, 1, 0, 0, 0, 342, 343, 5, 12, 0, 0, 343, 344, 3, 34, 17, 0, 344, 33, 1, 0, 0, 0, 345, 350, 3, 36, 18, 0, 346, 347, 5, 41, 0, 0, 347, 349, 3, 36, 18, 0, 348, 346, 1, 0, 0, 0, 349, 352, 1, 0, 0, 0, 350, 348, 1, 0, 0, 0, 350, 351, 1, 0, 0, 0, 351, 35, 1, 0, 0, 0, 352, 350, 1, 0, 0, 0, 353, 354, 3, 58, 29, 0, 354, 355, 5, 38, 0, 0, 355, 357, 1, 0, 0, 0, 356, 353, 1, 0, 0, 0, 356, 357, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 359, 3, 10, 5, 0, 359, 37, 1, 0, 0, 0, 360, 361, 5, 6, 0, 0, 361, 366, 3, 40, 20, 0, 362, 363, 5, 41, 0, 0, 363, 365, 3, 40, 20, 0, 364, 362, 1, 0, 0, 0, 365, 368, 1, 0, 0, 0, 366, 364, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 370, 1, 0, 0, 0, 368, 366, 1, 0, 0, 0, 369, 371, 3, 46, 23, 0, 370, 369, 1, 0, 0, 0, 370, 371, 1, 0, 0, 0, 371, 39, 1, 0, 0, 0, 372, 373, 3, 42, 21, 0, 373, 374, 5, 40, 0, 0, 374, 376, 1, 0, 0, 0, 375, 372, 1, 0, 0, 0, 375, 376, 1, 0, 0, 0, 376, 377, 1, 0, 0, 0, 377, 378, 3, 44, 22, 0, 378, 41, 1, 0, 0, 0, 379, 380, 7, 2, 0, 0, 380, 43, 1, 0, 0, 0, 381, 382, 7, 2, 0, 0, 382, 45, 1, 0, 0, 0, 383, 384, 5, 84, 0, 0, 384, 389, 5, 85, 0, 0, 385, 386, 5, 41, 0, 0, 386, 388, 5, 85, 0, 0, 387, 385, 1, 0, 0, 0, 388, 391, 1, 0, 0, 0, 389, 387, 1, 0, 0, 0, 389, 390, 1, 0, 0, 0, 390, 47, 1, 0, 0, 0, 391, 389, 1, 0, 0, 0, 392, 393, 5, 22, 0, 0, 393, 398, 3, 40, 20, 0, 394, 395, 5, 41, 0, 0, 395, 397, 3, 40, 20, 0, 396, 394, 1, 0, 0, 0, 397, 400, 1, 0, 0, 0, 398, 396, 1, 0, 0, 0, 398, 399, 1, 0, 0, 0, 399, 402, 1, 0, 0, 0, 400, 398, 1, 0, 0, 0, 401, 403, 3, 54, 27, 0, 402, 401, 1, 0, 0, 0, 402, 403, 1, 0, 0, 0, 403, 406, 1, 0, 0, 0, 404, 405, 5, 35, 0, 0, 405, 407, 3, 34, 17, 0, 406, 404, 1, 0, 0, 0, 406, 407, 1, 0, 0, 0, 407, 49, 1, 0, 0, 0, 408, 409, 5, 4, 0, 0, 409, 410, 3, 34, 17, 0, 410, 51, 1, 0, 0, 0, 411, 413, 5, 15, 0, 0, 412, 414, 3, 54, 27, 0, 413, 412, 1, 0, 0, 0, 413, 414, 1, 0, 0, 0, 414, 417, 1, 0, 0, 0, 415, 416, 5, 35, 0, 0, 416, 418, 3, 34, 17, 0, 417, 415, 1, 0, 0, 0, 417, 418, 1, 0, 0, 0, 418, 53, 1, 0, 0, 0, 419, 424, 3, 56, 28, 0, 420, 421, 5, 41, 0, 0, 421, 423, 3, 56, 28, 0, 422, 420, 1, 0, 0, 0, 423, 426, 1, 0, 0, 0, 424, 422, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, 425, 55, 1, 0, 0, 0, 426, 424, 1, 0, 0, 0, 427, 430, 3, 36, 18, 0, 428, 429, 5, 16, 0, 0, 429, 431, 3, 10, 5, 0, 430, 428, 1, 0, 0, 0, 430, 431, 1, 0, 0, 0, 431, 57, 1, 0, 0, 0, 432, 437, 3, 72, 36, 0, 433, 434, 5, 43, 0, 0, 434, 436, 3, 72, 36, 0, 435, 433, 1, 0, 0, 0, 436, 439, 1, 0, 0, 0, 437, 435, 1, 0, 0, 0, 437, 438, 1, 0, 0, 0, 438, 59, 1, 0, 0, 0, 439, 437, 1, 0, 0, 0, 440, 445, 3, 66, 33, 0, 441, 442, 5, 43, 0, 0, 442, 444, 3, 66, 33, 0, 443, 441, 1, 0, 0, 0, 444, 447, 1, 0, 0, 0, 445, 443, 1, 0, 0, 0, 445, 446, 1, 0, 0, 0, 446, 61, 1, 0, 0, 0, 447, 445, 1, 0, 0, 0, 448, 453, 3, 60, 30, 0, 449, 450, 5, 41, 0, 0, 450, 452, 3, 60, 30, 0, 451, 449, 1, 0, 0, 0, 452, 455, 1, 0, 0, 0, 453, 451, 1, 0, 0, 0, 453, 454, 1, 0, 0, 0, 454, 63, 1, 0, 0, 0, 455, 453, 1, 0, 0, 0, 456, 457, 7, 3, 0, 0, 457, 65, 1, 0, 0, 0, 458, 461, 5, 89, 0, 0, 459, 461, 3, 70, 35, 0, 460, 458, 1, 0, 0, 0, 460, 459, 1, 0, 0, 0, 461, 67, 1, 0, 0, 0, 462, 505, 5, 52, 0, 0, 463, 464, 3, 104, 52, 0, 464, 465, 5, 76, 0, 0, 465, 505, 1, 0, 0, 0, 466, 505, 3, 102, 51, 0, 467, 505, 3, 104, 52, 0, 468, 505, 3, 98, 49, 0, 469, 505, 3, 70, 35, 0, 470, 505, 3, 106, 53, 0, 471, 472, 5, 74, 0, 0, 472, 477, 3, 100, 50, 0, 473, 474, 5, 41, 0, 0, 474, 476, 3, 100, 50, 0, 475, 473, 1, 0, 0, 0, 476, 479, 1, 0, 0, 0, 477, 475, 1, 0, 0, 0, 477, 478, 1, 0, 0, 0, 478, 480, 1, 0, 0, 0, 479, 477, 1, 0, 0, 0, 480, 481, 5, 75, 0, 0, 481, 505, 1, 0, 0, 0, 482, 483, 5, 74, 0, 0, 483, 488, 3, 98, 49, 0, 484, 485, 5, 41, 0, 0, 485, 487, 3, 98, 49, 0, 486, 484, 1, 0, 0, 0, 487, 490, 1, 0, 0, 0, 488, 486, 1, 0, 0, 0, 488, 489, 1, 0, 0, 0, 489, 491, 1, 0, 0, 0, 490, 488, 1, 0, 0, 0, 491, 492, 5, 75, 0, 0, 492, 505, 1, 0, 0, 0, 493, 494, 5, 74, 0, 0, 494, 499, 3, 106, 53, 0, 495, 496, 5, 41, 0, 0, 496, 498, 3, 106, 53, 0, 497, 495, 1, 0, 0, 0, 498, 501, 1, 0, 0, 0, 499, 497, 1, 0, 0, 0, 499, 500, 1, 0, 0, 0, 500, 502, 1, 0, 0, 0, 501, 499, 1, 0, 0, 0, 502, 503, 5, 75, 0, 0, 503, 505, 1, 0, 0, 0, 504, 462, 1, 0, 0, 0, 504, 463, 1, 0, 0, 0, 504, 466, 1, 0, 0, 0, 504, 467, 1, 0, 0, 0, 504, 468, 1, 0, 0, 0, 504, 469, 1, 0, 0, 0, 504, 470, 1, 0, 0, 0, 504, 471, 1, 0, 0, 0, 504, 482, 1, 0, 0, 0, 504, 493, 1, 0, 0, 0, 505, 69, 1, 0, 0, 0, 506, 509, 5, 55, 0, 0, 507, 509, 5, 73, 0, 0, 508, 506, 1, 0, 0, 0, 508, 507, 1, 0, 0, 0, 509, 71, 1, 0, 0, 0, 510, 513, 3, 64, 32, 0, 511, 513, 3, 70, 35, 0, 512, 510, 1, 0, 0, 0, 512, 511, 1, 0, 0, 0, 513, 73, 1, 0, 0, 0, 514, 515, 5, 9, 0, 0, 515, 516, 5, 33, 0, 0, 516, 75, 1, 0, 0, 0, 517, 518, 5, 14, 0, 0, 518, 523, 3, 78, 39, 0, 519, 520, 5, 41, 0, 0, 520, 522, 3, 78, 39, 0, 521, 519, 1, 0, 0, 0, 522, 525, 1, 0, 0, 0, 523, 521, 1, 0, 0, 0, 523, 524, 1, 0, 0, 0, 524, 77, 1, 0, 0, 0, 525, 523, 1, 0, 0, 0, 526, 528, 3, 10, 5, 0, 527, 529, 7, 4, 0, 0, 528, 527, 1, 0, 0, 0, 528, 529, 1, 0, 0, 0, 529, 532, 1, 0, 0, 0, 530, 531, 5, 53, 0, 0, 531, 533, 7, 5, 0, 0, 532, 530, 1, 0, 0, 0, 532, 533, 1, 0, 0, 0, 533, 79, 1, 0, 0, 0, 534, 535, 5, 8, 0, 0, 535, 536, 3, 62, 31, 0, 536, 81, 1, 0, 0, 0, 537, 538, 5, 2, 0, 0, 538, 539, 3, 62, 31, 0, 539, 83, 1, 0, 0, 0, 540, 541, 5, 11, 0, 0, 541, 546, 3, 86, 43, 0, 542, 543, 5, 41, 0, 0, 543, 545, 3, 86, 43, 0, 544, 542, 1, 0, 0, 0, 545, 548, 1, 0, 0, 0, 546, 544, 1, 0, 0, 0, 546, 547, 1, 0, 0, 0, 547, 85, 1, 0, 0, 0, 548, 546, 1, 0, 0, 0, 549, 550, 3, 60, 30, 0, 550, 551, 5, 93, 0, 0, 551, 552, 3, 60, 30, 0, 552, 87, 1, 0, 0, 0, 553, 554, 5, 1, 0, 0, 554, 555, 3, 20, 10, 0, 555, 557, 3, 106, 53, 0, 556, 558, 3, 94, 47, 0, 557, 556, 1, 0, 0, 0, 557, 558, 1, 0, 0, 0, 558, 89, 1, 0, 0, 0, 559, 560, 5, 7, 0, 0, 560, 561, 3, 20, 10, 0, 561, 562, 3, 106, 53, 0, 562, 91, 1, 0, 0, 0, 563, 564, 5, 10, 0, 0, 564, 565, 3, 58, 29, 0, 565, 93, 1, 0, 0, 0, 566, 571, 3, 96, 48, 0, 567, 568, 5, 41, 0, 0, 568, 570, 3, 96, 48, 0, 569, 567, 1, 0, 0, 0, 570, 573, 1, 0, 0, 0, 571, 569, 1, 0, 0, 0, 571, 572, 1, 0, 0, 0, 572, 95, 1, 0, 0, 0, 573, 571, 1, 0, 0, 0, 574, 575, 3, 64, 32, 0, 575, 576, 5, 38, 0, 0, 576, 577, 3, 68, 34, 0, 577, 97, 1, 0, 0, 0, 578, 579, 7, 6, 0, 0, 579, 99, 1, 0, 0, 0, 580, 583, 3, 102, 51, 0, 581, 583, 3, 104, 52, 0, 582, 580, 1, 0, 0, 0, 582, 581, 1, 0, 0, 0, 583, 101, 1, 0, 0, 0, 584, 586, 7, 0, 0, 0, 585, 584, 1, 0, 0, 0, 585, 586, 1, 0, 0, 0, 586, 587, 1, 0, 0, 0, 587, 588, 5, 34, 0, 0, 588, 103, 1, 0, 0, 0, 589, 591, 7, 0, 0, 0, 590, 589, 1, 0, 0, 0, 590, 591, 1, 0, 0, 0, 591, 592, 1, 0, 0, 0, 592, 593, 5, 33, 0, 0, 593, 105, 1, 0, 0, 0, 594, 595, 5, 32, 0, 0, 595, 107, 1, 0, 0, 0, 596, 597, 7, 7, 0, 0, 597, 109, 1, 0, 0, 0, 598, 599, 5, 5, 0, 0, 599, 600, 3, 112, 56, 0, 600, 111, 1, 0, 0, 0, 601, 602, 5, 74, 0, 0, 602, 603, 3, 2, 1, 0, 603, 604, 5, 75, 0, 0, 604, 113, 1, 0, 0, 0, 605, 606, 5, 13, 0, 0, 606, 607, 5, 109, 0, 0, 607, 115, 1, 0, 0, 0, 608, 609, 5, 3, 0, 0, 609, 612, 5, 99, 0, 0, 610, 611, 5, 97, 0, 0, 611, 613, 3, 60, 30, 0, 612, 610, 1, 0, 0, 0, 612, 613, 1, 0, 0, 0, 613, 623, 1, 0, 0, 0, 614, 615, 5, 98, 0, 0, 615, 620, 3, 118, 59, 0, 616, 617, 5, 41, 0, 0, 617, 619, 3, 118, 59, 0, 618, 616, 1, 0, 0, 0, 619, 622, 1, 0, 0, 0, 620, 618, 1, 0, 0, 0, 620, 621, 1, 0, 0, 0, 621, 624, 1, 0, 0, 0, 622, 620, 1, 0, 0, 0, 623, 614, 1, 0, 0, 0, 623, 624, 1, 0, 0, 0, 624, 117, 1, 0, 0, 0, 625, 626, 3, 60, 30, 0, 626, 627, 5, 38, 0, 0, 627, 629, 1, 0, 0, 0, 628, 625, 1, 0, 0, 0, 628, 629, 1, 0, 0, 0, 629, 630, 1, 0, 0, 0, 630, 631, 3, 60, 30, 0, 631, 119, 1, 0, 0, 0, 632, 633, 5, 21, 0, 0, 633, 634, 3, 40, 20, 0, 634, 635, 5, 97, 0, 0, 635, 636, 3, 62, 31, 0, 636, 121, 1, 0, 0, 0, 637, 638, 5, 19, 0, 0, 638, 641, 3, 54, 27, 0, 639, 640, 5, 35, 0, 0, 640, 642, 3, 34, 17, 0, 641, 639, 1, 0, 0, 0, 641, 642, 1, 0, 0, 0, 642, 123, 1, 0, 0, 0, 643, 644, 7, 8, 0, 0, 644, 645, 5, 123, 0, 0, 645, 646, 3, 126, 63, 0, 646, 647, 3, 128, 64, 0, 647, 125, 1, 0, 0, 0, 648, 649, 3, 40, 20, 0, 649, 127, 1, 0, 0, 0, 650, 651, 5, 97, 0, 0, 651, 656, 3, 130, 65, 0, 652, 653, 5, 41, 0, 0, 653, 655, 3, 130, 65, 0, 654, 652, 1, 0, 0, 0, 655, 658, 1, 0, 0, 0, 656, 654, 1, 0, 0, 0, 656, 657, 1, 0, 0, 0, 657, 129, 1, 0, 0, 0, 658, 656, 1, 0, 0, 0, 659, 660, 3, 16, 8, 0, 660, 131, 1, 0, 0, 0, 661, 662, 5, 18, 0, 0, 662, 665, 3, 58, 29, 0, 663, 664, 5, 97, 0, 0, 664, 666, 3, 58, 29, 0, 665, 663, 1, 0, 0, 0, 665, 666, 1, 0, 0, 0, 666, 672, 1, 0, 0, 0, 667, 668, 5, 93, 0, 0, 668, 669, 3, 58, 29, 0, 669, 670, 5, 41, 0, 0, 670, 671, 3, 58, 29, 0, 671, 673, 1, 0, 0, 0, 672, 667, 1, 0, 0, 0, 672, 673, 1, 0, 0, 0, 673, 133, 1, 0, 0, 0, 674, 675, 5, 20, 0, 0, 675, 676, 3, 62, 31, 0, 676, 135, 1, 0, 0, 0, 677, 678, 5, 26, 0, 0, 678, 679, 3, 138, 69, 0, 679, 137, 1, 0, 0, 0, 680, 682, 3, 140, 70, 0, 681, 680, 1, 0, 0, 0, 682, 683, 1, 0, 0, 0, 683, 681, 1, 0, 0, 0, 683, 684, 1, 0, 0, 0, 684, 139, 1, 0, 0, 0, 685, 686, 5, 50, 0, 0, 686, 687, 3, 142, 71, 0, 687, 688, 5, 57, 0, 0, 688, 141, 1, 0, 0, 0, 689, 690, 6, 71, -1, 0, 690, 691, 3, 144, 72, 0, 691, 697, 1, 0, 0, 0, 692, 693, 10, 1, 0, 0, 693, 694, 5, 31, 0, 0, 694, 696, 3, 144, 72, 0, 695, 692, 1, 0, 0, 0, 696, 699, 1, 0, 0, 0, 697, 695, 1, 0, 0, 0, 697, 698, 1, 0, 0, 0, 698, 143, 1, 0, 0, 0, 699, 697, 1, 0, 0, 0, 700, 704, 3, 8, 4, 0, 701, 704, 3, 76, 38, 0, 702, 704, 3, 74, 37, 0, 703, 700, 1, 0, 0, 0, 703, 701, 1, 0, 0, 0, 703, 702, 1, 0, 0, 0, 704, 145, 1, 0, 0, 0, 66, 157, 166, 191, 203, 212, 220, 225, 233, 235, 240, 247, 252, 257, 267, 273, 281, 283, 294, 301, 312, 317, 319, 331, 350, 356, 366, 370, 375, 389, 398, 402, 406, 413, 417, 424, 430, 437, 445, 453, 460, 477, 488, 499, 504, 508, 512, 523, 528, 532, 546, 557, 571, 582, 585, 590, 612, 620, 623, 628, 641, 656, 665, 672, 683, 697, 703] \ No newline at end of file +[4, 1, 142, 706, 2, 0, 7, 0, 2, 1, 7, 1, 2, 2, 7, 2, 2, 3, 7, 3, 2, 4, 7, 4, 2, 5, 7, 5, 2, 6, 7, 6, 2, 7, 7, 7, 2, 8, 7, 8, 2, 9, 7, 9, 2, 10, 7, 10, 2, 11, 7, 11, 2, 12, 7, 12, 2, 13, 7, 13, 2, 14, 7, 14, 2, 15, 7, 15, 2, 16, 7, 16, 2, 17, 7, 17, 2, 18, 7, 18, 2, 19, 7, 19, 2, 20, 7, 20, 2, 21, 7, 21, 2, 22, 7, 22, 2, 23, 7, 23, 2, 24, 7, 24, 2, 25, 7, 25, 2, 26, 7, 26, 2, 27, 7, 27, 2, 28, 7, 28, 2, 29, 7, 29, 2, 30, 7, 30, 2, 31, 7, 31, 2, 32, 7, 32, 2, 33, 7, 33, 2, 34, 7, 34, 2, 35, 7, 35, 2, 36, 7, 36, 2, 37, 7, 37, 2, 38, 7, 38, 2, 39, 7, 39, 2, 40, 7, 40, 2, 41, 7, 41, 2, 42, 7, 42, 2, 43, 7, 43, 2, 44, 7, 44, 2, 45, 7, 45, 2, 46, 7, 46, 2, 47, 7, 47, 2, 48, 7, 48, 2, 49, 7, 49, 2, 50, 7, 50, 2, 51, 7, 51, 2, 52, 7, 52, 2, 53, 7, 53, 2, 54, 7, 54, 2, 55, 7, 55, 2, 56, 7, 56, 2, 57, 7, 57, 2, 58, 7, 58, 2, 59, 7, 59, 2, 60, 7, 60, 2, 61, 7, 61, 2, 62, 7, 62, 2, 63, 7, 63, 2, 64, 7, 64, 2, 65, 7, 65, 2, 66, 7, 66, 2, 67, 7, 67, 2, 68, 7, 68, 2, 69, 7, 69, 2, 70, 7, 70, 2, 71, 7, 71, 2, 72, 7, 72, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 5, 1, 156, 8, 1, 10, 1, 12, 1, 159, 9, 1, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 2, 167, 8, 2, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 1, 3, 3, 3, 192, 8, 3, 1, 4, 1, 4, 1, 4, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 204, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 211, 8, 5, 10, 5, 12, 5, 214, 9, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 3, 5, 221, 8, 5, 1, 5, 1, 5, 1, 5, 3, 5, 226, 8, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 1, 5, 5, 5, 234, 8, 5, 10, 5, 12, 5, 237, 9, 5, 1, 6, 1, 6, 3, 6, 241, 8, 6, 1, 6, 1, 6, 1, 6, 1, 6, 1, 6, 3, 6, 248, 8, 6, 1, 6, 1, 6, 1, 6, 3, 6, 253, 8, 6, 1, 7, 1, 7, 1, 7, 3, 7, 258, 8, 7, 1, 7, 1, 7, 1, 7, 1, 8, 1, 8, 1, 8, 1, 8, 1, 8, 3, 8, 268, 8, 8, 1, 9, 1, 9, 1, 9, 1, 9, 3, 9, 274, 8, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 1, 9, 5, 9, 282, 8, 9, 10, 9, 12, 9, 285, 9, 9, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 1, 10, 3, 10, 295, 8, 10, 1, 10, 1, 10, 1, 10, 5, 10, 300, 8, 10, 10, 10, 12, 10, 303, 9, 10, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 1, 11, 5, 11, 311, 8, 11, 10, 11, 12, 11, 314, 9, 11, 1, 11, 1, 11, 3, 11, 318, 8, 11, 3, 11, 320, 8, 11, 1, 11, 1, 11, 1, 12, 1, 12, 1, 13, 1, 13, 1, 13, 1, 13, 5, 13, 330, 8, 13, 10, 13, 12, 13, 333, 9, 13, 1, 13, 1, 13, 1, 14, 1, 14, 1, 14, 1, 14, 1, 15, 1, 15, 1, 16, 1, 16, 1, 16, 1, 17, 1, 17, 1, 17, 5, 17, 349, 8, 17, 10, 17, 12, 17, 352, 9, 17, 1, 18, 1, 18, 1, 18, 3, 18, 357, 8, 18, 1, 18, 1, 18, 1, 19, 1, 19, 1, 19, 1, 19, 5, 19, 365, 8, 19, 10, 19, 12, 19, 368, 9, 19, 1, 19, 3, 19, 371, 8, 19, 1, 20, 1, 20, 1, 20, 3, 20, 376, 8, 20, 1, 20, 1, 20, 1, 21, 1, 21, 1, 22, 1, 22, 1, 23, 1, 23, 1, 23, 1, 23, 5, 23, 388, 8, 23, 10, 23, 12, 23, 391, 9, 23, 1, 24, 1, 24, 1, 24, 1, 24, 5, 24, 397, 8, 24, 10, 24, 12, 24, 400, 9, 24, 1, 24, 3, 24, 403, 8, 24, 1, 24, 1, 24, 3, 24, 407, 8, 24, 1, 25, 1, 25, 1, 25, 1, 26, 1, 26, 3, 26, 414, 8, 26, 1, 26, 1, 26, 3, 26, 418, 8, 26, 1, 27, 1, 27, 1, 27, 5, 27, 423, 8, 27, 10, 27, 12, 27, 426, 9, 27, 1, 28, 1, 28, 1, 28, 3, 28, 431, 8, 28, 1, 29, 1, 29, 1, 29, 5, 29, 436, 8, 29, 10, 29, 12, 29, 439, 9, 29, 1, 30, 1, 30, 1, 30, 5, 30, 444, 8, 30, 10, 30, 12, 30, 447, 9, 30, 1, 31, 1, 31, 1, 31, 5, 31, 452, 8, 31, 10, 31, 12, 31, 455, 9, 31, 1, 32, 1, 32, 1, 33, 1, 33, 3, 33, 461, 8, 33, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 476, 8, 34, 10, 34, 12, 34, 479, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 487, 8, 34, 10, 34, 12, 34, 490, 9, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 1, 34, 5, 34, 498, 8, 34, 10, 34, 12, 34, 501, 9, 34, 1, 34, 1, 34, 3, 34, 505, 8, 34, 1, 35, 1, 35, 3, 35, 509, 8, 35, 1, 36, 1, 36, 3, 36, 513, 8, 36, 1, 37, 1, 37, 1, 37, 1, 38, 1, 38, 1, 38, 1, 38, 5, 38, 522, 8, 38, 10, 38, 12, 38, 525, 9, 38, 1, 39, 1, 39, 3, 39, 529, 8, 39, 1, 39, 1, 39, 3, 39, 533, 8, 39, 1, 40, 1, 40, 1, 40, 1, 41, 1, 41, 1, 41, 1, 42, 1, 42, 1, 42, 1, 42, 5, 42, 545, 8, 42, 10, 42, 12, 42, 548, 9, 42, 1, 43, 1, 43, 1, 43, 1, 43, 1, 44, 1, 44, 1, 44, 1, 44, 3, 44, 558, 8, 44, 1, 45, 1, 45, 1, 45, 1, 45, 1, 46, 1, 46, 1, 46, 1, 47, 1, 47, 1, 47, 5, 47, 570, 8, 47, 10, 47, 12, 47, 573, 9, 47, 1, 48, 1, 48, 1, 48, 1, 48, 1, 49, 1, 49, 1, 50, 1, 50, 3, 50, 583, 8, 50, 1, 51, 3, 51, 586, 8, 51, 1, 51, 1, 51, 1, 52, 3, 52, 591, 8, 52, 1, 52, 1, 52, 1, 53, 1, 53, 1, 54, 1, 54, 1, 55, 1, 55, 1, 55, 1, 56, 1, 56, 1, 56, 1, 56, 1, 57, 1, 57, 1, 57, 1, 58, 1, 58, 1, 58, 1, 58, 3, 58, 613, 8, 58, 1, 58, 1, 58, 1, 58, 1, 58, 5, 58, 619, 8, 58, 10, 58, 12, 58, 622, 9, 58, 3, 58, 624, 8, 58, 1, 59, 1, 59, 1, 59, 3, 59, 629, 8, 59, 1, 59, 1, 59, 1, 60, 1, 60, 1, 60, 1, 60, 1, 60, 1, 61, 1, 61, 1, 61, 1, 61, 3, 61, 642, 8, 61, 1, 62, 1, 62, 1, 62, 1, 62, 1, 62, 1, 63, 1, 63, 1, 64, 1, 64, 1, 64, 1, 64, 5, 64, 655, 8, 64, 10, 64, 12, 64, 658, 9, 64, 1, 65, 1, 65, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 666, 8, 66, 1, 66, 1, 66, 1, 66, 1, 66, 1, 66, 3, 66, 673, 8, 66, 1, 67, 1, 67, 1, 67, 1, 68, 1, 68, 1, 68, 1, 69, 4, 69, 682, 8, 69, 11, 69, 12, 69, 683, 1, 70, 1, 70, 1, 70, 1, 70, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 1, 71, 5, 71, 696, 8, 71, 10, 71, 12, 71, 699, 9, 71, 1, 72, 1, 72, 1, 72, 3, 72, 704, 8, 72, 1, 72, 0, 5, 2, 10, 18, 20, 142, 73, 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 140, 142, 144, 0, 9, 1, 0, 64, 65, 1, 0, 66, 68, 2, 0, 32, 32, 85, 85, 1, 0, 76, 77, 2, 0, 37, 37, 42, 42, 2, 0, 45, 45, 48, 48, 2, 0, 44, 44, 56, 56, 2, 0, 57, 57, 59, 63, 2, 0, 17, 17, 24, 25, 733, 0, 146, 1, 0, 0, 0, 2, 149, 1, 0, 0, 0, 4, 166, 1, 0, 0, 0, 6, 191, 1, 0, 0, 0, 8, 193, 1, 0, 0, 0, 10, 225, 1, 0, 0, 0, 12, 252, 1, 0, 0, 0, 14, 254, 1, 0, 0, 0, 16, 267, 1, 0, 0, 0, 18, 273, 1, 0, 0, 0, 20, 294, 1, 0, 0, 0, 22, 304, 1, 0, 0, 0, 24, 323, 1, 0, 0, 0, 26, 325, 1, 0, 0, 0, 28, 336, 1, 0, 0, 0, 30, 340, 1, 0, 0, 0, 32, 342, 1, 0, 0, 0, 34, 345, 1, 0, 0, 0, 36, 356, 1, 0, 0, 0, 38, 360, 1, 0, 0, 0, 40, 375, 1, 0, 0, 0, 42, 379, 1, 0, 0, 0, 44, 381, 1, 0, 0, 0, 46, 383, 1, 0, 0, 0, 48, 392, 1, 0, 0, 0, 50, 408, 1, 0, 0, 0, 52, 411, 1, 0, 0, 0, 54, 419, 1, 0, 0, 0, 56, 427, 1, 0, 0, 0, 58, 432, 1, 0, 0, 0, 60, 440, 1, 0, 0, 0, 62, 448, 1, 0, 0, 0, 64, 456, 1, 0, 0, 0, 66, 460, 1, 0, 0, 0, 68, 504, 1, 0, 0, 0, 70, 508, 1, 0, 0, 0, 72, 512, 1, 0, 0, 0, 74, 514, 1, 0, 0, 0, 76, 517, 1, 0, 0, 0, 78, 526, 1, 0, 0, 0, 80, 534, 1, 0, 0, 0, 82, 537, 1, 0, 0, 0, 84, 540, 1, 0, 0, 0, 86, 549, 1, 0, 0, 0, 88, 553, 1, 0, 0, 0, 90, 559, 1, 0, 0, 0, 92, 563, 1, 0, 0, 0, 94, 566, 1, 0, 0, 0, 96, 574, 1, 0, 0, 0, 98, 578, 1, 0, 0, 0, 100, 582, 1, 0, 0, 0, 102, 585, 1, 0, 0, 0, 104, 590, 1, 0, 0, 0, 106, 594, 1, 0, 0, 0, 108, 596, 1, 0, 0, 0, 110, 598, 1, 0, 0, 0, 112, 601, 1, 0, 0, 0, 114, 605, 1, 0, 0, 0, 116, 608, 1, 0, 0, 0, 118, 628, 1, 0, 0, 0, 120, 632, 1, 0, 0, 0, 122, 637, 1, 0, 0, 0, 124, 643, 1, 0, 0, 0, 126, 648, 1, 0, 0, 0, 128, 650, 1, 0, 0, 0, 130, 659, 1, 0, 0, 0, 132, 661, 1, 0, 0, 0, 134, 674, 1, 0, 0, 0, 136, 677, 1, 0, 0, 0, 138, 681, 1, 0, 0, 0, 140, 685, 1, 0, 0, 0, 142, 689, 1, 0, 0, 0, 144, 703, 1, 0, 0, 0, 146, 147, 3, 2, 1, 0, 147, 148, 5, 0, 0, 1, 148, 1, 1, 0, 0, 0, 149, 150, 6, 1, -1, 0, 150, 151, 3, 4, 2, 0, 151, 157, 1, 0, 0, 0, 152, 153, 10, 1, 0, 0, 153, 154, 5, 31, 0, 0, 154, 156, 3, 6, 3, 0, 155, 152, 1, 0, 0, 0, 156, 159, 1, 0, 0, 0, 157, 155, 1, 0, 0, 0, 157, 158, 1, 0, 0, 0, 158, 3, 1, 0, 0, 0, 159, 157, 1, 0, 0, 0, 160, 167, 3, 110, 55, 0, 161, 167, 3, 38, 19, 0, 162, 167, 3, 32, 16, 0, 163, 167, 3, 114, 57, 0, 164, 165, 4, 2, 1, 0, 165, 167, 3, 48, 24, 0, 166, 160, 1, 0, 0, 0, 166, 161, 1, 0, 0, 0, 166, 162, 1, 0, 0, 0, 166, 163, 1, 0, 0, 0, 166, 164, 1, 0, 0, 0, 167, 5, 1, 0, 0, 0, 168, 192, 3, 50, 25, 0, 169, 192, 3, 8, 4, 0, 170, 192, 3, 80, 40, 0, 171, 192, 3, 74, 37, 0, 172, 192, 3, 52, 26, 0, 173, 192, 3, 76, 38, 0, 174, 192, 3, 82, 41, 0, 175, 192, 3, 84, 42, 0, 176, 192, 3, 88, 44, 0, 177, 192, 3, 90, 45, 0, 178, 192, 3, 116, 58, 0, 179, 192, 3, 92, 46, 0, 180, 192, 3, 124, 62, 0, 181, 182, 4, 3, 2, 0, 182, 192, 3, 122, 61, 0, 183, 184, 4, 3, 3, 0, 184, 192, 3, 120, 60, 0, 185, 186, 4, 3, 4, 0, 186, 192, 3, 132, 66, 0, 187, 188, 4, 3, 5, 0, 188, 192, 3, 134, 67, 0, 189, 190, 4, 3, 6, 0, 190, 192, 3, 136, 68, 0, 191, 168, 1, 0, 0, 0, 191, 169, 1, 0, 0, 0, 191, 170, 1, 0, 0, 0, 191, 171, 1, 0, 0, 0, 191, 172, 1, 0, 0, 0, 191, 173, 1, 0, 0, 0, 191, 174, 1, 0, 0, 0, 191, 175, 1, 0, 0, 0, 191, 176, 1, 0, 0, 0, 191, 177, 1, 0, 0, 0, 191, 178, 1, 0, 0, 0, 191, 179, 1, 0, 0, 0, 191, 180, 1, 0, 0, 0, 191, 181, 1, 0, 0, 0, 191, 183, 1, 0, 0, 0, 191, 185, 1, 0, 0, 0, 191, 187, 1, 0, 0, 0, 191, 189, 1, 0, 0, 0, 192, 7, 1, 0, 0, 0, 193, 194, 5, 16, 0, 0, 194, 195, 3, 10, 5, 0, 195, 9, 1, 0, 0, 0, 196, 197, 6, 5, -1, 0, 197, 198, 5, 50, 0, 0, 198, 226, 3, 10, 5, 8, 199, 226, 3, 16, 8, 0, 200, 226, 3, 12, 6, 0, 201, 203, 3, 16, 8, 0, 202, 204, 5, 50, 0, 0, 203, 202, 1, 0, 0, 0, 203, 204, 1, 0, 0, 0, 204, 205, 1, 0, 0, 0, 205, 206, 5, 46, 0, 0, 206, 207, 5, 74, 0, 0, 207, 212, 3, 16, 8, 0, 208, 209, 5, 41, 0, 0, 209, 211, 3, 16, 8, 0, 210, 208, 1, 0, 0, 0, 211, 214, 1, 0, 0, 0, 212, 210, 1, 0, 0, 0, 212, 213, 1, 0, 0, 0, 213, 215, 1, 0, 0, 0, 214, 212, 1, 0, 0, 0, 215, 216, 5, 75, 0, 0, 216, 226, 1, 0, 0, 0, 217, 218, 3, 16, 8, 0, 218, 220, 5, 47, 0, 0, 219, 221, 5, 50, 0, 0, 220, 219, 1, 0, 0, 0, 220, 221, 1, 0, 0, 0, 221, 222, 1, 0, 0, 0, 222, 223, 5, 51, 0, 0, 223, 226, 1, 0, 0, 0, 224, 226, 3, 14, 7, 0, 225, 196, 1, 0, 0, 0, 225, 199, 1, 0, 0, 0, 225, 200, 1, 0, 0, 0, 225, 201, 1, 0, 0, 0, 225, 217, 1, 0, 0, 0, 225, 224, 1, 0, 0, 0, 226, 235, 1, 0, 0, 0, 227, 228, 10, 5, 0, 0, 228, 229, 5, 36, 0, 0, 229, 234, 3, 10, 5, 6, 230, 231, 10, 4, 0, 0, 231, 232, 5, 53, 0, 0, 232, 234, 3, 10, 5, 5, 233, 227, 1, 0, 0, 0, 233, 230, 1, 0, 0, 0, 234, 237, 1, 0, 0, 0, 235, 233, 1, 0, 0, 0, 235, 236, 1, 0, 0, 0, 236, 11, 1, 0, 0, 0, 237, 235, 1, 0, 0, 0, 238, 240, 3, 16, 8, 0, 239, 241, 5, 50, 0, 0, 240, 239, 1, 0, 0, 0, 240, 241, 1, 0, 0, 0, 241, 242, 1, 0, 0, 0, 242, 243, 5, 49, 0, 0, 243, 244, 3, 106, 53, 0, 244, 253, 1, 0, 0, 0, 245, 247, 3, 16, 8, 0, 246, 248, 5, 50, 0, 0, 247, 246, 1, 0, 0, 0, 247, 248, 1, 0, 0, 0, 248, 249, 1, 0, 0, 0, 249, 250, 5, 55, 0, 0, 250, 251, 3, 106, 53, 0, 251, 253, 1, 0, 0, 0, 252, 238, 1, 0, 0, 0, 252, 245, 1, 0, 0, 0, 253, 13, 1, 0, 0, 0, 254, 257, 3, 58, 29, 0, 255, 256, 5, 39, 0, 0, 256, 258, 3, 30, 15, 0, 257, 255, 1, 0, 0, 0, 257, 258, 1, 0, 0, 0, 258, 259, 1, 0, 0, 0, 259, 260, 5, 40, 0, 0, 260, 261, 3, 68, 34, 0, 261, 15, 1, 0, 0, 0, 262, 268, 3, 18, 9, 0, 263, 264, 3, 18, 9, 0, 264, 265, 3, 108, 54, 0, 265, 266, 3, 18, 9, 0, 266, 268, 1, 0, 0, 0, 267, 262, 1, 0, 0, 0, 267, 263, 1, 0, 0, 0, 268, 17, 1, 0, 0, 0, 269, 270, 6, 9, -1, 0, 270, 274, 3, 20, 10, 0, 271, 272, 7, 0, 0, 0, 272, 274, 3, 18, 9, 3, 273, 269, 1, 0, 0, 0, 273, 271, 1, 0, 0, 0, 274, 283, 1, 0, 0, 0, 275, 276, 10, 2, 0, 0, 276, 277, 7, 1, 0, 0, 277, 282, 3, 18, 9, 3, 278, 279, 10, 1, 0, 0, 279, 280, 7, 0, 0, 0, 280, 282, 3, 18, 9, 2, 281, 275, 1, 0, 0, 0, 281, 278, 1, 0, 0, 0, 282, 285, 1, 0, 0, 0, 283, 281, 1, 0, 0, 0, 283, 284, 1, 0, 0, 0, 284, 19, 1, 0, 0, 0, 285, 283, 1, 0, 0, 0, 286, 287, 6, 10, -1, 0, 287, 295, 3, 68, 34, 0, 288, 295, 3, 58, 29, 0, 289, 295, 3, 22, 11, 0, 290, 291, 5, 74, 0, 0, 291, 292, 3, 10, 5, 0, 292, 293, 5, 75, 0, 0, 293, 295, 1, 0, 0, 0, 294, 286, 1, 0, 0, 0, 294, 288, 1, 0, 0, 0, 294, 289, 1, 0, 0, 0, 294, 290, 1, 0, 0, 0, 295, 301, 1, 0, 0, 0, 296, 297, 10, 1, 0, 0, 297, 298, 5, 39, 0, 0, 298, 300, 3, 30, 15, 0, 299, 296, 1, 0, 0, 0, 300, 303, 1, 0, 0, 0, 301, 299, 1, 0, 0, 0, 301, 302, 1, 0, 0, 0, 302, 21, 1, 0, 0, 0, 303, 301, 1, 0, 0, 0, 304, 305, 3, 24, 12, 0, 305, 319, 5, 74, 0, 0, 306, 320, 5, 66, 0, 0, 307, 312, 3, 10, 5, 0, 308, 309, 5, 41, 0, 0, 309, 311, 3, 10, 5, 0, 310, 308, 1, 0, 0, 0, 311, 314, 1, 0, 0, 0, 312, 310, 1, 0, 0, 0, 312, 313, 1, 0, 0, 0, 313, 317, 1, 0, 0, 0, 314, 312, 1, 0, 0, 0, 315, 316, 5, 41, 0, 0, 316, 318, 3, 26, 13, 0, 317, 315, 1, 0, 0, 0, 317, 318, 1, 0, 0, 0, 318, 320, 1, 0, 0, 0, 319, 306, 1, 0, 0, 0, 319, 307, 1, 0, 0, 0, 319, 320, 1, 0, 0, 0, 320, 321, 1, 0, 0, 0, 321, 322, 5, 75, 0, 0, 322, 23, 1, 0, 0, 0, 323, 324, 3, 72, 36, 0, 324, 25, 1, 0, 0, 0, 325, 326, 5, 69, 0, 0, 326, 331, 3, 28, 14, 0, 327, 328, 5, 41, 0, 0, 328, 330, 3, 28, 14, 0, 329, 327, 1, 0, 0, 0, 330, 333, 1, 0, 0, 0, 331, 329, 1, 0, 0, 0, 331, 332, 1, 0, 0, 0, 332, 334, 1, 0, 0, 0, 333, 331, 1, 0, 0, 0, 334, 335, 5, 70, 0, 0, 335, 27, 1, 0, 0, 0, 336, 337, 3, 106, 53, 0, 337, 338, 5, 40, 0, 0, 338, 339, 3, 68, 34, 0, 339, 29, 1, 0, 0, 0, 340, 341, 3, 64, 32, 0, 341, 31, 1, 0, 0, 0, 342, 343, 5, 12, 0, 0, 343, 344, 3, 34, 17, 0, 344, 33, 1, 0, 0, 0, 345, 350, 3, 36, 18, 0, 346, 347, 5, 41, 0, 0, 347, 349, 3, 36, 18, 0, 348, 346, 1, 0, 0, 0, 349, 352, 1, 0, 0, 0, 350, 348, 1, 0, 0, 0, 350, 351, 1, 0, 0, 0, 351, 35, 1, 0, 0, 0, 352, 350, 1, 0, 0, 0, 353, 354, 3, 58, 29, 0, 354, 355, 5, 38, 0, 0, 355, 357, 1, 0, 0, 0, 356, 353, 1, 0, 0, 0, 356, 357, 1, 0, 0, 0, 357, 358, 1, 0, 0, 0, 358, 359, 3, 10, 5, 0, 359, 37, 1, 0, 0, 0, 360, 361, 5, 6, 0, 0, 361, 366, 3, 40, 20, 0, 362, 363, 5, 41, 0, 0, 363, 365, 3, 40, 20, 0, 364, 362, 1, 0, 0, 0, 365, 368, 1, 0, 0, 0, 366, 364, 1, 0, 0, 0, 366, 367, 1, 0, 0, 0, 367, 370, 1, 0, 0, 0, 368, 366, 1, 0, 0, 0, 369, 371, 3, 46, 23, 0, 370, 369, 1, 0, 0, 0, 370, 371, 1, 0, 0, 0, 371, 39, 1, 0, 0, 0, 372, 373, 3, 42, 21, 0, 373, 374, 5, 40, 0, 0, 374, 376, 1, 0, 0, 0, 375, 372, 1, 0, 0, 0, 375, 376, 1, 0, 0, 0, 376, 377, 1, 0, 0, 0, 377, 378, 3, 44, 22, 0, 378, 41, 1, 0, 0, 0, 379, 380, 7, 2, 0, 0, 380, 43, 1, 0, 0, 0, 381, 382, 7, 2, 0, 0, 382, 45, 1, 0, 0, 0, 383, 384, 5, 84, 0, 0, 384, 389, 5, 85, 0, 0, 385, 386, 5, 41, 0, 0, 386, 388, 5, 85, 0, 0, 387, 385, 1, 0, 0, 0, 388, 391, 1, 0, 0, 0, 389, 387, 1, 0, 0, 0, 389, 390, 1, 0, 0, 0, 390, 47, 1, 0, 0, 0, 391, 389, 1, 0, 0, 0, 392, 393, 5, 22, 0, 0, 393, 398, 3, 40, 20, 0, 394, 395, 5, 41, 0, 0, 395, 397, 3, 40, 20, 0, 396, 394, 1, 0, 0, 0, 397, 400, 1, 0, 0, 0, 398, 396, 1, 0, 0, 0, 398, 399, 1, 0, 0, 0, 399, 402, 1, 0, 0, 0, 400, 398, 1, 0, 0, 0, 401, 403, 3, 54, 27, 0, 402, 401, 1, 0, 0, 0, 402, 403, 1, 0, 0, 0, 403, 406, 1, 0, 0, 0, 404, 405, 5, 35, 0, 0, 405, 407, 3, 34, 17, 0, 406, 404, 1, 0, 0, 0, 406, 407, 1, 0, 0, 0, 407, 49, 1, 0, 0, 0, 408, 409, 5, 4, 0, 0, 409, 410, 3, 34, 17, 0, 410, 51, 1, 0, 0, 0, 411, 413, 5, 15, 0, 0, 412, 414, 3, 54, 27, 0, 413, 412, 1, 0, 0, 0, 413, 414, 1, 0, 0, 0, 414, 417, 1, 0, 0, 0, 415, 416, 5, 35, 0, 0, 416, 418, 3, 34, 17, 0, 417, 415, 1, 0, 0, 0, 417, 418, 1, 0, 0, 0, 418, 53, 1, 0, 0, 0, 419, 424, 3, 56, 28, 0, 420, 421, 5, 41, 0, 0, 421, 423, 3, 56, 28, 0, 422, 420, 1, 0, 0, 0, 423, 426, 1, 0, 0, 0, 424, 422, 1, 0, 0, 0, 424, 425, 1, 0, 0, 0, 425, 55, 1, 0, 0, 0, 426, 424, 1, 0, 0, 0, 427, 430, 3, 36, 18, 0, 428, 429, 5, 16, 0, 0, 429, 431, 3, 10, 5, 0, 430, 428, 1, 0, 0, 0, 430, 431, 1, 0, 0, 0, 431, 57, 1, 0, 0, 0, 432, 437, 3, 72, 36, 0, 433, 434, 5, 43, 0, 0, 434, 436, 3, 72, 36, 0, 435, 433, 1, 0, 0, 0, 436, 439, 1, 0, 0, 0, 437, 435, 1, 0, 0, 0, 437, 438, 1, 0, 0, 0, 438, 59, 1, 0, 0, 0, 439, 437, 1, 0, 0, 0, 440, 445, 3, 66, 33, 0, 441, 442, 5, 43, 0, 0, 442, 444, 3, 66, 33, 0, 443, 441, 1, 0, 0, 0, 444, 447, 1, 0, 0, 0, 445, 443, 1, 0, 0, 0, 445, 446, 1, 0, 0, 0, 446, 61, 1, 0, 0, 0, 447, 445, 1, 0, 0, 0, 448, 453, 3, 60, 30, 0, 449, 450, 5, 41, 0, 0, 450, 452, 3, 60, 30, 0, 451, 449, 1, 0, 0, 0, 452, 455, 1, 0, 0, 0, 453, 451, 1, 0, 0, 0, 453, 454, 1, 0, 0, 0, 454, 63, 1, 0, 0, 0, 455, 453, 1, 0, 0, 0, 456, 457, 7, 3, 0, 0, 457, 65, 1, 0, 0, 0, 458, 461, 5, 89, 0, 0, 459, 461, 3, 70, 35, 0, 460, 458, 1, 0, 0, 0, 460, 459, 1, 0, 0, 0, 461, 67, 1, 0, 0, 0, 462, 505, 5, 51, 0, 0, 463, 464, 3, 104, 52, 0, 464, 465, 5, 76, 0, 0, 465, 505, 1, 0, 0, 0, 466, 505, 3, 102, 51, 0, 467, 505, 3, 104, 52, 0, 468, 505, 3, 98, 49, 0, 469, 505, 3, 70, 35, 0, 470, 505, 3, 106, 53, 0, 471, 472, 5, 72, 0, 0, 472, 477, 3, 100, 50, 0, 473, 474, 5, 41, 0, 0, 474, 476, 3, 100, 50, 0, 475, 473, 1, 0, 0, 0, 476, 479, 1, 0, 0, 0, 477, 475, 1, 0, 0, 0, 477, 478, 1, 0, 0, 0, 478, 480, 1, 0, 0, 0, 479, 477, 1, 0, 0, 0, 480, 481, 5, 73, 0, 0, 481, 505, 1, 0, 0, 0, 482, 483, 5, 72, 0, 0, 483, 488, 3, 98, 49, 0, 484, 485, 5, 41, 0, 0, 485, 487, 3, 98, 49, 0, 486, 484, 1, 0, 0, 0, 487, 490, 1, 0, 0, 0, 488, 486, 1, 0, 0, 0, 488, 489, 1, 0, 0, 0, 489, 491, 1, 0, 0, 0, 490, 488, 1, 0, 0, 0, 491, 492, 5, 73, 0, 0, 492, 505, 1, 0, 0, 0, 493, 494, 5, 72, 0, 0, 494, 499, 3, 106, 53, 0, 495, 496, 5, 41, 0, 0, 496, 498, 3, 106, 53, 0, 497, 495, 1, 0, 0, 0, 498, 501, 1, 0, 0, 0, 499, 497, 1, 0, 0, 0, 499, 500, 1, 0, 0, 0, 500, 502, 1, 0, 0, 0, 501, 499, 1, 0, 0, 0, 502, 503, 5, 73, 0, 0, 503, 505, 1, 0, 0, 0, 504, 462, 1, 0, 0, 0, 504, 463, 1, 0, 0, 0, 504, 466, 1, 0, 0, 0, 504, 467, 1, 0, 0, 0, 504, 468, 1, 0, 0, 0, 504, 469, 1, 0, 0, 0, 504, 470, 1, 0, 0, 0, 504, 471, 1, 0, 0, 0, 504, 482, 1, 0, 0, 0, 504, 493, 1, 0, 0, 0, 505, 69, 1, 0, 0, 0, 506, 509, 5, 54, 0, 0, 507, 509, 5, 71, 0, 0, 508, 506, 1, 0, 0, 0, 508, 507, 1, 0, 0, 0, 509, 71, 1, 0, 0, 0, 510, 513, 3, 64, 32, 0, 511, 513, 3, 70, 35, 0, 512, 510, 1, 0, 0, 0, 512, 511, 1, 0, 0, 0, 513, 73, 1, 0, 0, 0, 514, 515, 5, 9, 0, 0, 515, 516, 5, 33, 0, 0, 516, 75, 1, 0, 0, 0, 517, 518, 5, 14, 0, 0, 518, 523, 3, 78, 39, 0, 519, 520, 5, 41, 0, 0, 520, 522, 3, 78, 39, 0, 521, 519, 1, 0, 0, 0, 522, 525, 1, 0, 0, 0, 523, 521, 1, 0, 0, 0, 523, 524, 1, 0, 0, 0, 524, 77, 1, 0, 0, 0, 525, 523, 1, 0, 0, 0, 526, 528, 3, 10, 5, 0, 527, 529, 7, 4, 0, 0, 528, 527, 1, 0, 0, 0, 528, 529, 1, 0, 0, 0, 529, 532, 1, 0, 0, 0, 530, 531, 5, 52, 0, 0, 531, 533, 7, 5, 0, 0, 532, 530, 1, 0, 0, 0, 532, 533, 1, 0, 0, 0, 533, 79, 1, 0, 0, 0, 534, 535, 5, 8, 0, 0, 535, 536, 3, 62, 31, 0, 536, 81, 1, 0, 0, 0, 537, 538, 5, 2, 0, 0, 538, 539, 3, 62, 31, 0, 539, 83, 1, 0, 0, 0, 540, 541, 5, 11, 0, 0, 541, 546, 3, 86, 43, 0, 542, 543, 5, 41, 0, 0, 543, 545, 3, 86, 43, 0, 544, 542, 1, 0, 0, 0, 545, 548, 1, 0, 0, 0, 546, 544, 1, 0, 0, 0, 546, 547, 1, 0, 0, 0, 547, 85, 1, 0, 0, 0, 548, 546, 1, 0, 0, 0, 549, 550, 3, 60, 30, 0, 550, 551, 5, 93, 0, 0, 551, 552, 3, 60, 30, 0, 552, 87, 1, 0, 0, 0, 553, 554, 5, 1, 0, 0, 554, 555, 3, 20, 10, 0, 555, 557, 3, 106, 53, 0, 556, 558, 3, 94, 47, 0, 557, 556, 1, 0, 0, 0, 557, 558, 1, 0, 0, 0, 558, 89, 1, 0, 0, 0, 559, 560, 5, 7, 0, 0, 560, 561, 3, 20, 10, 0, 561, 562, 3, 106, 53, 0, 562, 91, 1, 0, 0, 0, 563, 564, 5, 10, 0, 0, 564, 565, 3, 58, 29, 0, 565, 93, 1, 0, 0, 0, 566, 571, 3, 96, 48, 0, 567, 568, 5, 41, 0, 0, 568, 570, 3, 96, 48, 0, 569, 567, 1, 0, 0, 0, 570, 573, 1, 0, 0, 0, 571, 569, 1, 0, 0, 0, 571, 572, 1, 0, 0, 0, 572, 95, 1, 0, 0, 0, 573, 571, 1, 0, 0, 0, 574, 575, 3, 64, 32, 0, 575, 576, 5, 38, 0, 0, 576, 577, 3, 68, 34, 0, 577, 97, 1, 0, 0, 0, 578, 579, 7, 6, 0, 0, 579, 99, 1, 0, 0, 0, 580, 583, 3, 102, 51, 0, 581, 583, 3, 104, 52, 0, 582, 580, 1, 0, 0, 0, 582, 581, 1, 0, 0, 0, 583, 101, 1, 0, 0, 0, 584, 586, 7, 0, 0, 0, 585, 584, 1, 0, 0, 0, 585, 586, 1, 0, 0, 0, 586, 587, 1, 0, 0, 0, 587, 588, 5, 34, 0, 0, 588, 103, 1, 0, 0, 0, 589, 591, 7, 0, 0, 0, 590, 589, 1, 0, 0, 0, 590, 591, 1, 0, 0, 0, 591, 592, 1, 0, 0, 0, 592, 593, 5, 33, 0, 0, 593, 105, 1, 0, 0, 0, 594, 595, 5, 32, 0, 0, 595, 107, 1, 0, 0, 0, 596, 597, 7, 7, 0, 0, 597, 109, 1, 0, 0, 0, 598, 599, 5, 5, 0, 0, 599, 600, 3, 112, 56, 0, 600, 111, 1, 0, 0, 0, 601, 602, 5, 72, 0, 0, 602, 603, 3, 2, 1, 0, 603, 604, 5, 73, 0, 0, 604, 113, 1, 0, 0, 0, 605, 606, 5, 13, 0, 0, 606, 607, 5, 109, 0, 0, 607, 115, 1, 0, 0, 0, 608, 609, 5, 3, 0, 0, 609, 612, 5, 99, 0, 0, 610, 611, 5, 97, 0, 0, 611, 613, 3, 60, 30, 0, 612, 610, 1, 0, 0, 0, 612, 613, 1, 0, 0, 0, 613, 623, 1, 0, 0, 0, 614, 615, 5, 98, 0, 0, 615, 620, 3, 118, 59, 0, 616, 617, 5, 41, 0, 0, 617, 619, 3, 118, 59, 0, 618, 616, 1, 0, 0, 0, 619, 622, 1, 0, 0, 0, 620, 618, 1, 0, 0, 0, 620, 621, 1, 0, 0, 0, 621, 624, 1, 0, 0, 0, 622, 620, 1, 0, 0, 0, 623, 614, 1, 0, 0, 0, 623, 624, 1, 0, 0, 0, 624, 117, 1, 0, 0, 0, 625, 626, 3, 60, 30, 0, 626, 627, 5, 38, 0, 0, 627, 629, 1, 0, 0, 0, 628, 625, 1, 0, 0, 0, 628, 629, 1, 0, 0, 0, 629, 630, 1, 0, 0, 0, 630, 631, 3, 60, 30, 0, 631, 119, 1, 0, 0, 0, 632, 633, 5, 21, 0, 0, 633, 634, 3, 40, 20, 0, 634, 635, 5, 97, 0, 0, 635, 636, 3, 62, 31, 0, 636, 121, 1, 0, 0, 0, 637, 638, 5, 19, 0, 0, 638, 641, 3, 54, 27, 0, 639, 640, 5, 35, 0, 0, 640, 642, 3, 34, 17, 0, 641, 639, 1, 0, 0, 0, 641, 642, 1, 0, 0, 0, 642, 123, 1, 0, 0, 0, 643, 644, 7, 8, 0, 0, 644, 645, 5, 123, 0, 0, 645, 646, 3, 126, 63, 0, 646, 647, 3, 128, 64, 0, 647, 125, 1, 0, 0, 0, 648, 649, 3, 40, 20, 0, 649, 127, 1, 0, 0, 0, 650, 651, 5, 97, 0, 0, 651, 656, 3, 130, 65, 0, 652, 653, 5, 41, 0, 0, 653, 655, 3, 130, 65, 0, 654, 652, 1, 0, 0, 0, 655, 658, 1, 0, 0, 0, 656, 654, 1, 0, 0, 0, 656, 657, 1, 0, 0, 0, 657, 129, 1, 0, 0, 0, 658, 656, 1, 0, 0, 0, 659, 660, 3, 16, 8, 0, 660, 131, 1, 0, 0, 0, 661, 662, 5, 18, 0, 0, 662, 665, 3, 58, 29, 0, 663, 664, 5, 97, 0, 0, 664, 666, 3, 58, 29, 0, 665, 663, 1, 0, 0, 0, 665, 666, 1, 0, 0, 0, 666, 672, 1, 0, 0, 0, 667, 668, 5, 93, 0, 0, 668, 669, 3, 58, 29, 0, 669, 670, 5, 41, 0, 0, 670, 671, 3, 58, 29, 0, 671, 673, 1, 0, 0, 0, 672, 667, 1, 0, 0, 0, 672, 673, 1, 0, 0, 0, 673, 133, 1, 0, 0, 0, 674, 675, 5, 20, 0, 0, 675, 676, 3, 62, 31, 0, 676, 135, 1, 0, 0, 0, 677, 678, 5, 26, 0, 0, 678, 679, 3, 138, 69, 0, 679, 137, 1, 0, 0, 0, 680, 682, 3, 140, 70, 0, 681, 680, 1, 0, 0, 0, 682, 683, 1, 0, 0, 0, 683, 681, 1, 0, 0, 0, 683, 684, 1, 0, 0, 0, 684, 139, 1, 0, 0, 0, 685, 686, 5, 74, 0, 0, 686, 687, 3, 142, 71, 0, 687, 688, 5, 75, 0, 0, 688, 141, 1, 0, 0, 0, 689, 690, 6, 71, -1, 0, 690, 691, 3, 144, 72, 0, 691, 697, 1, 0, 0, 0, 692, 693, 10, 1, 0, 0, 693, 694, 5, 31, 0, 0, 694, 696, 3, 144, 72, 0, 695, 692, 1, 0, 0, 0, 696, 699, 1, 0, 0, 0, 697, 695, 1, 0, 0, 0, 697, 698, 1, 0, 0, 0, 698, 143, 1, 0, 0, 0, 699, 697, 1, 0, 0, 0, 700, 704, 3, 8, 4, 0, 701, 704, 3, 76, 38, 0, 702, 704, 3, 74, 37, 0, 703, 700, 1, 0, 0, 0, 703, 701, 1, 0, 0, 0, 703, 702, 1, 0, 0, 0, 704, 145, 1, 0, 0, 0, 66, 157, 166, 191, 203, 212, 220, 225, 233, 235, 240, 247, 252, 257, 267, 273, 281, 283, 294, 301, 312, 317, 319, 331, 350, 356, 366, 370, 375, 389, 398, 402, 406, 413, 417, 424, 430, 437, 445, 453, 460, 477, 488, 499, 504, 508, 512, 523, 528, 532, 546, 557, 571, 582, 585, 590, 612, 620, 623, 628, 641, 656, 665, 672, 683, 697, 703] \ No newline at end of file diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java index 533b2793bb15..2c03f767c58a 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/parser/EsqlBaseParser.java @@ -32,21 +32,21 @@ public class EsqlBaseParser extends ParserConfig { DEV_FORK=26, UNKNOWN_CMD=27, LINE_COMMENT=28, MULTILINE_COMMENT=29, WS=30, PIPE=31, QUOTED_STRING=32, INTEGER_LITERAL=33, DECIMAL_LITERAL=34, BY=35, AND=36, ASC=37, ASSIGN=38, CAST_OP=39, COLON=40, COMMA=41, DESC=42, DOT=43, - FALSE=44, FIRST=45, IN=46, IS=47, LAST=48, LIKE=49, LP=50, NOT=51, NULL=52, - NULLS=53, OR=54, PARAM=55, RLIKE=56, RP=57, TRUE=58, EQ=59, CIEQ=60, NEQ=61, - LT=62, LTE=63, GT=64, GTE=65, PLUS=66, MINUS=67, ASTERISK=68, SLASH=69, - PERCENT=70, LEFT_BRACES=71, RIGHT_BRACES=72, NAMED_OR_POSITIONAL_PARAM=73, - OPENING_BRACKET=74, CLOSING_BRACKET=75, UNQUOTED_IDENTIFIER=76, QUOTED_IDENTIFIER=77, - EXPR_LINE_COMMENT=78, EXPR_MULTILINE_COMMENT=79, EXPR_WS=80, EXPLAIN_WS=81, - EXPLAIN_LINE_COMMENT=82, EXPLAIN_MULTILINE_COMMENT=83, METADATA=84, UNQUOTED_SOURCE=85, - FROM_LINE_COMMENT=86, FROM_MULTILINE_COMMENT=87, FROM_WS=88, ID_PATTERN=89, - PROJECT_LINE_COMMENT=90, PROJECT_MULTILINE_COMMENT=91, PROJECT_WS=92, - AS=93, RENAME_LINE_COMMENT=94, RENAME_MULTILINE_COMMENT=95, RENAME_WS=96, - ON=97, WITH=98, ENRICH_POLICY_NAME=99, ENRICH_LINE_COMMENT=100, ENRICH_MULTILINE_COMMENT=101, - ENRICH_WS=102, ENRICH_FIELD_LINE_COMMENT=103, ENRICH_FIELD_MULTILINE_COMMENT=104, - ENRICH_FIELD_WS=105, MVEXPAND_LINE_COMMENT=106, MVEXPAND_MULTILINE_COMMENT=107, - MVEXPAND_WS=108, INFO=109, SHOW_LINE_COMMENT=110, SHOW_MULTILINE_COMMENT=111, - SHOW_WS=112, SETTING=113, SETTING_LINE_COMMENT=114, SETTTING_MULTILINE_COMMENT=115, + FALSE=44, FIRST=45, IN=46, IS=47, LAST=48, LIKE=49, NOT=50, NULL=51, NULLS=52, + OR=53, PARAM=54, RLIKE=55, TRUE=56, EQ=57, CIEQ=58, NEQ=59, LT=60, LTE=61, + GT=62, GTE=63, PLUS=64, MINUS=65, ASTERISK=66, SLASH=67, PERCENT=68, LEFT_BRACES=69, + RIGHT_BRACES=70, NAMED_OR_POSITIONAL_PARAM=71, OPENING_BRACKET=72, CLOSING_BRACKET=73, + LP=74, RP=75, UNQUOTED_IDENTIFIER=76, QUOTED_IDENTIFIER=77, EXPR_LINE_COMMENT=78, + EXPR_MULTILINE_COMMENT=79, EXPR_WS=80, EXPLAIN_WS=81, EXPLAIN_LINE_COMMENT=82, + EXPLAIN_MULTILINE_COMMENT=83, METADATA=84, UNQUOTED_SOURCE=85, FROM_LINE_COMMENT=86, + FROM_MULTILINE_COMMENT=87, FROM_WS=88, ID_PATTERN=89, PROJECT_LINE_COMMENT=90, + PROJECT_MULTILINE_COMMENT=91, PROJECT_WS=92, AS=93, RENAME_LINE_COMMENT=94, + RENAME_MULTILINE_COMMENT=95, RENAME_WS=96, ON=97, WITH=98, ENRICH_POLICY_NAME=99, + ENRICH_LINE_COMMENT=100, ENRICH_MULTILINE_COMMENT=101, ENRICH_WS=102, + ENRICH_FIELD_LINE_COMMENT=103, ENRICH_FIELD_MULTILINE_COMMENT=104, ENRICH_FIELD_WS=105, + MVEXPAND_LINE_COMMENT=106, MVEXPAND_MULTILINE_COMMENT=107, MVEXPAND_WS=108, + INFO=109, SHOW_LINE_COMMENT=110, SHOW_MULTILINE_COMMENT=111, SHOW_WS=112, + SETTING=113, SETTING_LINE_COMMENT=114, SETTTING_MULTILINE_COMMENT=115, SETTING_WS=116, LOOKUP_LINE_COMMENT=117, LOOKUP_MULTILINE_COMMENT=118, LOOKUP_WS=119, LOOKUP_FIELD_LINE_COMMENT=120, LOOKUP_FIELD_MULTILINE_COMMENT=121, LOOKUP_FIELD_WS=122, JOIN=123, USING=124, JOIN_LINE_COMMENT=125, JOIN_MULTILINE_COMMENT=126, @@ -108,10 +108,10 @@ public class EsqlBaseParser extends ParserConfig { "'sort'", "'stats'", "'where'", "'lookup'", null, null, null, null, null, null, null, null, null, null, null, null, null, "'|'", null, null, null, "'by'", "'and'", "'asc'", "'='", "'::'", "':'", "','", "'desc'", "'.'", - "'false'", "'first'", "'in'", "'is'", "'last'", "'like'", "'('", "'not'", - "'null'", "'nulls'", "'or'", "'?'", "'rlike'", "')'", "'true'", "'=='", - "'=~'", "'!='", "'<'", "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", - "'%'", "'{'", "'}'", null, null, "']'", null, null, null, null, null, + "'false'", "'first'", "'in'", "'is'", "'last'", "'like'", "'not'", "'null'", + "'nulls'", "'or'", "'?'", "'rlike'", "'true'", "'=='", "'=~'", "'!='", + "'<'", "'<='", "'>'", "'>='", "'+'", "'-'", "'*'", "'/'", "'%'", "'{'", + "'}'", null, null, "']'", null, "')'", null, null, null, null, null, null, null, null, "'metadata'", null, null, null, null, null, null, null, null, "'as'", null, null, null, "'on'", "'with'", null, null, null, null, null, null, null, null, null, null, "'info'", null, null, null, null, @@ -128,17 +128,17 @@ public class EsqlBaseParser extends ParserConfig { "DEV_FORK", "UNKNOWN_CMD", "LINE_COMMENT", "MULTILINE_COMMENT", "WS", "PIPE", "QUOTED_STRING", "INTEGER_LITERAL", "DECIMAL_LITERAL", "BY", "AND", "ASC", "ASSIGN", "CAST_OP", "COLON", "COMMA", "DESC", "DOT", "FALSE", - "FIRST", "IN", "IS", "LAST", "LIKE", "LP", "NOT", "NULL", "NULLS", "OR", - "PARAM", "RLIKE", "RP", "TRUE", "EQ", "CIEQ", "NEQ", "LT", "LTE", "GT", - "GTE", "PLUS", "MINUS", "ASTERISK", "SLASH", "PERCENT", "LEFT_BRACES", - "RIGHT_BRACES", "NAMED_OR_POSITIONAL_PARAM", "OPENING_BRACKET", "CLOSING_BRACKET", - "UNQUOTED_IDENTIFIER", "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", "EXPR_MULTILINE_COMMENT", - "EXPR_WS", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", "EXPLAIN_MULTILINE_COMMENT", - "METADATA", "UNQUOTED_SOURCE", "FROM_LINE_COMMENT", "FROM_MULTILINE_COMMENT", - "FROM_WS", "ID_PATTERN", "PROJECT_LINE_COMMENT", "PROJECT_MULTILINE_COMMENT", - "PROJECT_WS", "AS", "RENAME_LINE_COMMENT", "RENAME_MULTILINE_COMMENT", - "RENAME_WS", "ON", "WITH", "ENRICH_POLICY_NAME", "ENRICH_LINE_COMMENT", - "ENRICH_MULTILINE_COMMENT", "ENRICH_WS", "ENRICH_FIELD_LINE_COMMENT", + "FIRST", "IN", "IS", "LAST", "LIKE", "NOT", "NULL", "NULLS", "OR", "PARAM", + "RLIKE", "TRUE", "EQ", "CIEQ", "NEQ", "LT", "LTE", "GT", "GTE", "PLUS", + "MINUS", "ASTERISK", "SLASH", "PERCENT", "LEFT_BRACES", "RIGHT_BRACES", + "NAMED_OR_POSITIONAL_PARAM", "OPENING_BRACKET", "CLOSING_BRACKET", "LP", + "RP", "UNQUOTED_IDENTIFIER", "QUOTED_IDENTIFIER", "EXPR_LINE_COMMENT", + "EXPR_MULTILINE_COMMENT", "EXPR_WS", "EXPLAIN_WS", "EXPLAIN_LINE_COMMENT", + "EXPLAIN_MULTILINE_COMMENT", "METADATA", "UNQUOTED_SOURCE", "FROM_LINE_COMMENT", + "FROM_MULTILINE_COMMENT", "FROM_WS", "ID_PATTERN", "PROJECT_LINE_COMMENT", + "PROJECT_MULTILINE_COMMENT", "PROJECT_WS", "AS", "RENAME_LINE_COMMENT", + "RENAME_MULTILINE_COMMENT", "RENAME_WS", "ON", "WITH", "ENRICH_POLICY_NAME", + "ENRICH_LINE_COMMENT", "ENRICH_MULTILINE_COMMENT", "ENRICH_WS", "ENRICH_FIELD_LINE_COMMENT", "ENRICH_FIELD_MULTILINE_COMMENT", "ENRICH_FIELD_WS", "MVEXPAND_LINE_COMMENT", "MVEXPAND_MULTILINE_COMMENT", "MVEXPAND_WS", "INFO", "SHOW_LINE_COMMENT", "SHOW_MULTILINE_COMMENT", "SHOW_WS", "SETTING", "SETTING_LINE_COMMENT", @@ -1557,7 +1557,7 @@ public class EsqlBaseParser extends ParserConfig { setState(276); ((ArithmeticBinaryContext)_localctx).operator = _input.LT(1); _la = _input.LA(1); - if ( !(((((_la - 68)) & ~0x3f) == 0 && ((1L << (_la - 68)) & 7L) != 0)) ) { + if ( !(((((_la - 66)) & ~0x3f) == 0 && ((1L << (_la - 66)) & 7L) != 0)) ) { ((ArithmeticBinaryContext)_localctx).operator = (Token)_errHandler.recoverInline(this); } else { @@ -1901,7 +1901,6 @@ public class EsqlBaseParser extends ParserConfig { case INTEGER_LITERAL: case DECIMAL_LITERAL: case FALSE: - case LP: case NOT: case NULL: case PARAM: @@ -1910,6 +1909,7 @@ public class EsqlBaseParser extends ParserConfig { case MINUS: case NAMED_OR_POSITIONAL_PARAM: case OPENING_BRACKET: + case LP: case UNQUOTED_IDENTIFIER: case QUOTED_IDENTIFIER: { @@ -5055,7 +5055,7 @@ public class EsqlBaseParser extends ParserConfig { { setState(596); _la = _input.LA(1); - if ( !(((((_la - 59)) & ~0x3f) == 0 && ((1L << (_la - 59)) & 125L) != 0)) ) { + if ( !((((_la) & ~0x3f) == 0 && ((1L << _la) & -432345564227567616L) != 0)) ) { _errHandler.recoverInline(this); } else { @@ -6449,8 +6449,8 @@ public class EsqlBaseParser extends ParserConfig { "\u0002\n\u0012\u0014\u008eI\u0000\u0002\u0004\u0006\b\n\f\u000e\u0010"+ "\u0012\u0014\u0016\u0018\u001a\u001c\u001e \"$&(*,.02468:<>@BDFHJLNPR"+ "TVXZ\\^`bdfhjlnprtvxz|~\u0080\u0082\u0084\u0086\u0088\u008a\u008c\u008e"+ - "\u0090\u0000\t\u0001\u0000BC\u0001\u0000DF\u0002\u0000 UU\u0001\u0000"+ - "LM\u0002\u0000%%**\u0002\u0000--00\u0002\u0000,,::\u0002\u0000;;=A\u0002"+ + "\u0090\u0000\t\u0001\u0000@A\u0001\u0000BD\u0002\u0000 UU\u0001\u0000"+ + "LM\u0002\u0000%%**\u0002\u0000--00\u0002\u0000,,88\u0002\u000099;?\u0002"+ "\u0000\u0011\u0011\u0018\u0019\u02dd\u0000\u0092\u0001\u0000\u0000\u0000"+ "\u0002\u0095\u0001\u0000\u0000\u0000\u0004\u00a6\u0001\u0000\u0000\u0000"+ "\u0006\u00bf\u0001\u0000\u0000\u0000\b\u00c1\u0001\u0000\u0000\u0000\n"+ @@ -6518,38 +6518,38 @@ public class EsqlBaseParser extends ParserConfig { "\u00bf\u00bb\u0001\u0000\u0000\u0000\u00bf\u00bd\u0001\u0000\u0000\u0000"+ "\u00c0\u0007\u0001\u0000\u0000\u0000\u00c1\u00c2\u0005\u0010\u0000\u0000"+ "\u00c2\u00c3\u0003\n\u0005\u0000\u00c3\t\u0001\u0000\u0000\u0000\u00c4"+ - "\u00c5\u0006\u0005\uffff\uffff\u0000\u00c5\u00c6\u00053\u0000\u0000\u00c6"+ + "\u00c5\u0006\u0005\uffff\uffff\u0000\u00c5\u00c6\u00052\u0000\u0000\u00c6"+ "\u00e2\u0003\n\u0005\b\u00c7\u00e2\u0003\u0010\b\u0000\u00c8\u00e2\u0003"+ - "\f\u0006\u0000\u00c9\u00cb\u0003\u0010\b\u0000\u00ca\u00cc\u00053\u0000"+ + "\f\u0006\u0000\u00c9\u00cb\u0003\u0010\b\u0000\u00ca\u00cc\u00052\u0000"+ "\u0000\u00cb\u00ca\u0001\u0000\u0000\u0000\u00cb\u00cc\u0001\u0000\u0000"+ "\u0000\u00cc\u00cd\u0001\u0000\u0000\u0000\u00cd\u00ce\u0005.\u0000\u0000"+ - "\u00ce\u00cf\u00052\u0000\u0000\u00cf\u00d4\u0003\u0010\b\u0000\u00d0"+ + "\u00ce\u00cf\u0005J\u0000\u0000\u00cf\u00d4\u0003\u0010\b\u0000\u00d0"+ "\u00d1\u0005)\u0000\u0000\u00d1\u00d3\u0003\u0010\b\u0000\u00d2\u00d0"+ "\u0001\u0000\u0000\u0000\u00d3\u00d6\u0001\u0000\u0000\u0000\u00d4\u00d2"+ "\u0001\u0000\u0000\u0000\u00d4\u00d5\u0001\u0000\u0000\u0000\u00d5\u00d7"+ "\u0001\u0000\u0000\u0000\u00d6\u00d4\u0001\u0000\u0000\u0000\u00d7\u00d8"+ - "\u00059\u0000\u0000\u00d8\u00e2\u0001\u0000\u0000\u0000\u00d9\u00da\u0003"+ - "\u0010\b\u0000\u00da\u00dc\u0005/\u0000\u0000\u00db\u00dd\u00053\u0000"+ + "\u0005K\u0000\u0000\u00d8\u00e2\u0001\u0000\u0000\u0000\u00d9\u00da\u0003"+ + "\u0010\b\u0000\u00da\u00dc\u0005/\u0000\u0000\u00db\u00dd\u00052\u0000"+ "\u0000\u00dc\u00db\u0001\u0000\u0000\u0000\u00dc\u00dd\u0001\u0000\u0000"+ - "\u0000\u00dd\u00de\u0001\u0000\u0000\u0000\u00de\u00df\u00054\u0000\u0000"+ + "\u0000\u00dd\u00de\u0001\u0000\u0000\u0000\u00de\u00df\u00053\u0000\u0000"+ "\u00df\u00e2\u0001\u0000\u0000\u0000\u00e0\u00e2\u0003\u000e\u0007\u0000"+ "\u00e1\u00c4\u0001\u0000\u0000\u0000\u00e1\u00c7\u0001\u0000\u0000\u0000"+ "\u00e1\u00c8\u0001\u0000\u0000\u0000\u00e1\u00c9\u0001\u0000\u0000\u0000"+ "\u00e1\u00d9\u0001\u0000\u0000\u0000\u00e1\u00e0\u0001\u0000\u0000\u0000"+ "\u00e2\u00eb\u0001\u0000\u0000\u0000\u00e3\u00e4\n\u0005\u0000\u0000\u00e4"+ "\u00e5\u0005$\u0000\u0000\u00e5\u00ea\u0003\n\u0005\u0006\u00e6\u00e7"+ - "\n\u0004\u0000\u0000\u00e7\u00e8\u00056\u0000\u0000\u00e8\u00ea\u0003"+ + "\n\u0004\u0000\u0000\u00e7\u00e8\u00055\u0000\u0000\u00e8\u00ea\u0003"+ "\n\u0005\u0005\u00e9\u00e3\u0001\u0000\u0000\u0000\u00e9\u00e6\u0001\u0000"+ "\u0000\u0000\u00ea\u00ed\u0001\u0000\u0000\u0000\u00eb\u00e9\u0001\u0000"+ "\u0000\u0000\u00eb\u00ec\u0001\u0000\u0000\u0000\u00ec\u000b\u0001\u0000"+ "\u0000\u0000\u00ed\u00eb\u0001\u0000\u0000\u0000\u00ee\u00f0\u0003\u0010"+ - "\b\u0000\u00ef\u00f1\u00053\u0000\u0000\u00f0\u00ef\u0001\u0000\u0000"+ + "\b\u0000\u00ef\u00f1\u00052\u0000\u0000\u00f0\u00ef\u0001\u0000\u0000"+ "\u0000\u00f0\u00f1\u0001\u0000\u0000\u0000\u00f1\u00f2\u0001\u0000\u0000"+ "\u0000\u00f2\u00f3\u00051\u0000\u0000\u00f3\u00f4\u0003j5\u0000\u00f4"+ "\u00fd\u0001\u0000\u0000\u0000\u00f5\u00f7\u0003\u0010\b\u0000\u00f6\u00f8"+ - "\u00053\u0000\u0000\u00f7\u00f6\u0001\u0000\u0000\u0000\u00f7\u00f8\u0001"+ + "\u00052\u0000\u0000\u00f7\u00f6\u0001\u0000\u0000\u0000\u00f7\u00f8\u0001"+ "\u0000\u0000\u0000\u00f8\u00f9\u0001\u0000\u0000\u0000\u00f9\u00fa\u0005"+ - "8\u0000\u0000\u00fa\u00fb\u0003j5\u0000\u00fb\u00fd\u0001\u0000\u0000"+ + "7\u0000\u0000\u00fa\u00fb\u0003j5\u0000\u00fb\u00fd\u0001\u0000\u0000"+ "\u0000\u00fc\u00ee\u0001\u0000\u0000\u0000\u00fc\u00f5\u0001\u0000\u0000"+ "\u0000\u00fd\r\u0001\u0000\u0000\u0000\u00fe\u0101\u0003:\u001d\u0000"+ "\u00ff\u0100\u0005\'\u0000\u0000\u0100\u0102\u0003\u001e\u000f\u0000\u0101"+ @@ -6571,8 +6571,8 @@ public class EsqlBaseParser extends ParserConfig { "\u011c\u0013\u0001\u0000\u0000\u0000\u011d\u011b\u0001\u0000\u0000\u0000"+ "\u011e\u011f\u0006\n\uffff\uffff\u0000\u011f\u0127\u0003D\"\u0000\u0120"+ "\u0127\u0003:\u001d\u0000\u0121\u0127\u0003\u0016\u000b\u0000\u0122\u0123"+ - "\u00052\u0000\u0000\u0123\u0124\u0003\n\u0005\u0000\u0124\u0125\u0005"+ - "9\u0000\u0000\u0125\u0127\u0001\u0000\u0000\u0000\u0126\u011e\u0001\u0000"+ + "\u0005J\u0000\u0000\u0123\u0124\u0003\n\u0005\u0000\u0124\u0125\u0005"+ + "K\u0000\u0000\u0125\u0127\u0001\u0000\u0000\u0000\u0126\u011e\u0001\u0000"+ "\u0000\u0000\u0126\u0120\u0001\u0000\u0000\u0000\u0126\u0121\u0001\u0000"+ "\u0000\u0000\u0126\u0122\u0001\u0000\u0000\u0000\u0127\u012d\u0001\u0000"+ "\u0000\u0000\u0128\u0129\n\u0001\u0000\u0000\u0129\u012a\u0005\'\u0000"+ @@ -6580,7 +6580,7 @@ public class EsqlBaseParser extends ParserConfig { "\u0000\u012c\u012f\u0001\u0000\u0000\u0000\u012d\u012b\u0001\u0000\u0000"+ "\u0000\u012d\u012e\u0001\u0000\u0000\u0000\u012e\u0015\u0001\u0000\u0000"+ "\u0000\u012f\u012d\u0001\u0000\u0000\u0000\u0130\u0131\u0003\u0018\f\u0000"+ - "\u0131\u013f\u00052\u0000\u0000\u0132\u0140\u0005D\u0000\u0000\u0133\u0138"+ + "\u0131\u013f\u0005J\u0000\u0000\u0132\u0140\u0005B\u0000\u0000\u0133\u0138"+ "\u0003\n\u0005\u0000\u0134\u0135\u0005)\u0000\u0000\u0135\u0137\u0003"+ "\n\u0005\u0000\u0136\u0134\u0001\u0000\u0000\u0000\u0137\u013a\u0001\u0000"+ "\u0000\u0000\u0138\u0136\u0001\u0000\u0000\u0000\u0138\u0139\u0001\u0000"+ @@ -6589,14 +6589,14 @@ public class EsqlBaseParser extends ParserConfig { "\u0000\u013d\u013b\u0001\u0000\u0000\u0000\u013d\u013e\u0001\u0000\u0000"+ "\u0000\u013e\u0140\u0001\u0000\u0000\u0000\u013f\u0132\u0001\u0000\u0000"+ "\u0000\u013f\u0133\u0001\u0000\u0000\u0000\u013f\u0140\u0001\u0000\u0000"+ - "\u0000\u0140\u0141\u0001\u0000\u0000\u0000\u0141\u0142\u00059\u0000\u0000"+ + "\u0000\u0140\u0141\u0001\u0000\u0000\u0000\u0141\u0142\u0005K\u0000\u0000"+ "\u0142\u0017\u0001\u0000\u0000\u0000\u0143\u0144\u0003H$\u0000\u0144\u0019"+ - "\u0001\u0000\u0000\u0000\u0145\u0146\u0005G\u0000\u0000\u0146\u014b\u0003"+ + "\u0001\u0000\u0000\u0000\u0145\u0146\u0005E\u0000\u0000\u0146\u014b\u0003"+ "\u001c\u000e\u0000\u0147\u0148\u0005)\u0000\u0000\u0148\u014a\u0003\u001c"+ "\u000e\u0000\u0149\u0147\u0001\u0000\u0000\u0000\u014a\u014d\u0001\u0000"+ "\u0000\u0000\u014b\u0149\u0001\u0000\u0000\u0000\u014b\u014c\u0001\u0000"+ "\u0000\u0000\u014c\u014e\u0001\u0000\u0000\u0000\u014d\u014b\u0001\u0000"+ - "\u0000\u0000\u014e\u014f\u0005H\u0000\u0000\u014f\u001b\u0001\u0000\u0000"+ + "\u0000\u0000\u014e\u014f\u0005F\u0000\u0000\u014f\u001b\u0001\u0000\u0000"+ "\u0000\u0150\u0151\u0003j5\u0000\u0151\u0152\u0005(\u0000\u0000\u0152"+ "\u0153\u0003D\"\u0000\u0153\u001d\u0001\u0000\u0000\u0000\u0154\u0155"+ "\u0003@ \u0000\u0155\u001f\u0001\u0000\u0000\u0000\u0156\u0157\u0005\f"+ @@ -6663,33 +6663,33 @@ public class EsqlBaseParser extends ParserConfig { "\u0000\u01c8\u01c9\u0007\u0003\u0000\u0000\u01c9A\u0001\u0000\u0000\u0000"+ "\u01ca\u01cd\u0005Y\u0000\u0000\u01cb\u01cd\u0003F#\u0000\u01cc\u01ca"+ "\u0001\u0000\u0000\u0000\u01cc\u01cb\u0001\u0000\u0000\u0000\u01cdC\u0001"+ - "\u0000\u0000\u0000\u01ce\u01f9\u00054\u0000\u0000\u01cf\u01d0\u0003h4"+ + "\u0000\u0000\u0000\u01ce\u01f9\u00053\u0000\u0000\u01cf\u01d0\u0003h4"+ "\u0000\u01d0\u01d1\u0005L\u0000\u0000\u01d1\u01f9\u0001\u0000\u0000\u0000"+ "\u01d2\u01f9\u0003f3\u0000\u01d3\u01f9\u0003h4\u0000\u01d4\u01f9\u0003"+ "b1\u0000\u01d5\u01f9\u0003F#\u0000\u01d6\u01f9\u0003j5\u0000\u01d7\u01d8"+ - "\u0005J\u0000\u0000\u01d8\u01dd\u0003d2\u0000\u01d9\u01da\u0005)\u0000"+ + "\u0005H\u0000\u0000\u01d8\u01dd\u0003d2\u0000\u01d9\u01da\u0005)\u0000"+ "\u0000\u01da\u01dc\u0003d2\u0000\u01db\u01d9\u0001\u0000\u0000\u0000\u01dc"+ "\u01df\u0001\u0000\u0000\u0000\u01dd\u01db\u0001\u0000\u0000\u0000\u01dd"+ "\u01de\u0001\u0000\u0000\u0000\u01de\u01e0\u0001\u0000\u0000\u0000\u01df"+ - "\u01dd\u0001\u0000\u0000\u0000\u01e0\u01e1\u0005K\u0000\u0000\u01e1\u01f9"+ - "\u0001\u0000\u0000\u0000\u01e2\u01e3\u0005J\u0000\u0000\u01e3\u01e8\u0003"+ + "\u01dd\u0001\u0000\u0000\u0000\u01e0\u01e1\u0005I\u0000\u0000\u01e1\u01f9"+ + "\u0001\u0000\u0000\u0000\u01e2\u01e3\u0005H\u0000\u0000\u01e3\u01e8\u0003"+ "b1\u0000\u01e4\u01e5\u0005)\u0000\u0000\u01e5\u01e7\u0003b1\u0000\u01e6"+ "\u01e4\u0001\u0000\u0000\u0000\u01e7\u01ea\u0001\u0000\u0000\u0000\u01e8"+ "\u01e6\u0001\u0000\u0000\u0000\u01e8\u01e9\u0001\u0000\u0000\u0000\u01e9"+ "\u01eb\u0001\u0000\u0000\u0000\u01ea\u01e8\u0001\u0000\u0000\u0000\u01eb"+ - "\u01ec\u0005K\u0000\u0000\u01ec\u01f9\u0001\u0000\u0000\u0000\u01ed\u01ee"+ - "\u0005J\u0000\u0000\u01ee\u01f3\u0003j5\u0000\u01ef\u01f0\u0005)\u0000"+ + "\u01ec\u0005I\u0000\u0000\u01ec\u01f9\u0001\u0000\u0000\u0000\u01ed\u01ee"+ + "\u0005H\u0000\u0000\u01ee\u01f3\u0003j5\u0000\u01ef\u01f0\u0005)\u0000"+ "\u0000\u01f0\u01f2\u0003j5\u0000\u01f1\u01ef\u0001\u0000\u0000\u0000\u01f2"+ "\u01f5\u0001\u0000\u0000\u0000\u01f3\u01f1\u0001\u0000\u0000\u0000\u01f3"+ "\u01f4\u0001\u0000\u0000\u0000\u01f4\u01f6\u0001\u0000\u0000\u0000\u01f5"+ - "\u01f3\u0001\u0000\u0000\u0000\u01f6\u01f7\u0005K\u0000\u0000\u01f7\u01f9"+ + "\u01f3\u0001\u0000\u0000\u0000\u01f6\u01f7\u0005I\u0000\u0000\u01f7\u01f9"+ "\u0001\u0000\u0000\u0000\u01f8\u01ce\u0001\u0000\u0000\u0000\u01f8\u01cf"+ "\u0001\u0000\u0000\u0000\u01f8\u01d2\u0001\u0000\u0000\u0000\u01f8\u01d3"+ "\u0001\u0000\u0000\u0000\u01f8\u01d4\u0001\u0000\u0000\u0000\u01f8\u01d5"+ "\u0001\u0000\u0000\u0000\u01f8\u01d6\u0001\u0000\u0000\u0000\u01f8\u01d7"+ "\u0001\u0000\u0000\u0000\u01f8\u01e2\u0001\u0000\u0000\u0000\u01f8\u01ed"+ "\u0001\u0000\u0000\u0000\u01f9E\u0001\u0000\u0000\u0000\u01fa\u01fd\u0005"+ - "7\u0000\u0000\u01fb\u01fd\u0005I\u0000\u0000\u01fc\u01fa\u0001\u0000\u0000"+ + "6\u0000\u0000\u01fb\u01fd\u0005G\u0000\u0000\u01fc\u01fa\u0001\u0000\u0000"+ "\u0000\u01fc\u01fb\u0001\u0000\u0000\u0000\u01fdG\u0001\u0000\u0000\u0000"+ "\u01fe\u0201\u0003@ \u0000\u01ff\u0201\u0003F#\u0000\u0200\u01fe\u0001"+ "\u0000\u0000\u0000\u0200\u01ff\u0001\u0000\u0000\u0000\u0201I\u0001\u0000"+ @@ -6701,7 +6701,7 @@ public class EsqlBaseParser extends ParserConfig { "\u0000\u0000\u0000\u020cM\u0001\u0000\u0000\u0000\u020d\u020b\u0001\u0000"+ "\u0000\u0000\u020e\u0210\u0003\n\u0005\u0000\u020f\u0211\u0007\u0004\u0000"+ "\u0000\u0210\u020f\u0001\u0000\u0000\u0000\u0210\u0211\u0001\u0000\u0000"+ - "\u0000\u0211\u0214\u0001\u0000\u0000\u0000\u0212\u0213\u00055\u0000\u0000"+ + "\u0000\u0211\u0214\u0001\u0000\u0000\u0000\u0212\u0213\u00054\u0000\u0000"+ "\u0213\u0215\u0007\u0005\u0000\u0000\u0214\u0212\u0001\u0000\u0000\u0000"+ "\u0214\u0215\u0001\u0000\u0000\u0000\u0215O\u0001\u0000\u0000\u0000\u0216"+ "\u0217\u0005\b\u0000\u0000\u0217\u0218\u0003>\u001f\u0000\u0218Q\u0001"+ @@ -6736,8 +6736,8 @@ public class EsqlBaseParser extends ParserConfig { "\u0000\u0251i\u0001\u0000\u0000\u0000\u0252\u0253\u0005 \u0000\u0000\u0253"+ "k\u0001\u0000\u0000\u0000\u0254\u0255\u0007\u0007\u0000\u0000\u0255m\u0001"+ "\u0000\u0000\u0000\u0256\u0257\u0005\u0005\u0000\u0000\u0257\u0258\u0003"+ - "p8\u0000\u0258o\u0001\u0000\u0000\u0000\u0259\u025a\u0005J\u0000\u0000"+ - "\u025a\u025b\u0003\u0002\u0001\u0000\u025b\u025c\u0005K\u0000\u0000\u025c"+ + "p8\u0000\u0258o\u0001\u0000\u0000\u0000\u0259\u025a\u0005H\u0000\u0000"+ + "\u025a\u025b\u0003\u0002\u0001\u0000\u025b\u025c\u0005I\u0000\u0000\u025c"+ "q\u0001\u0000\u0000\u0000\u025d\u025e\u0005\r\u0000\u0000\u025e\u025f"+ "\u0005m\u0000\u0000\u025fs\u0001\u0000\u0000\u0000\u0260\u0261\u0005\u0003"+ "\u0000\u0000\u0261\u0264\u0005c\u0000\u0000\u0262\u0263\u0005a\u0000\u0000"+ @@ -6779,8 +6779,8 @@ public class EsqlBaseParser extends ParserConfig { "\u02a7\u0089\u0001\u0000\u0000\u0000\u02a8\u02aa\u0003\u008cF\u0000\u02a9"+ "\u02a8\u0001\u0000\u0000\u0000\u02aa\u02ab\u0001\u0000\u0000\u0000\u02ab"+ "\u02a9\u0001\u0000\u0000\u0000\u02ab\u02ac\u0001\u0000\u0000\u0000\u02ac"+ - "\u008b\u0001\u0000\u0000\u0000\u02ad\u02ae\u00052\u0000\u0000\u02ae\u02af"+ - "\u0003\u008eG\u0000\u02af\u02b0\u00059\u0000\u0000\u02b0\u008d\u0001\u0000"+ + "\u008b\u0001\u0000\u0000\u0000\u02ad\u02ae\u0005J\u0000\u0000\u02ae\u02af"+ + "\u0003\u008eG\u0000\u02af\u02b0\u0005K\u0000\u0000\u02b0\u008d\u0001\u0000"+ "\u0000\u0000\u02b1\u02b2\u0006G\uffff\uffff\u0000\u02b2\u02b3\u0003\u0090"+ "H\u0000\u02b3\u02b9\u0001\u0000\u0000\u0000\u02b4\u02b5\n\u0001\u0000"+ "\u0000\u02b5\u02b6\u0005\u001f\u0000\u0000\u02b6\u02b8\u0003\u0090H\u0000"+ diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java index a1e421b80d60..50ef33381a65 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/parser/StatementParserTests.java @@ -3085,7 +3085,28 @@ public class StatementParserTests extends AbstractStatementParserTests { "line 1:20: mismatched input 'FORK' expecting {'limit', 'sort', 'where'}" ); expectError("FROM foo* | FORK ( x+1 ) ( WHERE y>2 )", "line 1:20: mismatched input 'x+1' expecting {'limit', 'sort', 'where'}"); - expectError("FROM foo* | FORK ( LIMIT 10 ) ( y+2 )", "line 1:33: mismatched input 'y' expecting {'limit', 'sort', 'where'}"); + expectError("FROM foo* | FORK ( LIMIT 10 ) ( y+2 )", "line 1:33: mismatched input 'y+2' expecting {'limit', 'sort', 'where'}"); + } + + public void testFieldNamesAsCommands() throws Exception { + String[] keywords = new String[] { + "dissect", + "drop", + "enrich", + "eval", + "explain", + "from", + "grok", + "keep", + "limit", + "mv_expand", + "rename", + "sort", + "stats" }; + for (String keyword : keywords) { + var plan = statement("FROM test | STATS avg(" + keyword + ")"); + var aggregate = as(plan, Aggregate.class); + } } static Alias alias(String name, Expression value) { From 4e15a4d786e98f3f498d109a3ed27ae5db3c49d3 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 22 Feb 2025 02:20:44 +1100 Subject: [PATCH 11/27] Mute org.elasticsearch.index.mapper.extras.ScaledFloatFieldMapperTests testBlockLoaderFromColumnReaderWithSyntheticSource #123149 --- muted-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index b1ed5bc53969..3344b6e4335b 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -341,6 +341,9 @@ tests: - class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT method: testStopQueryLocal issue: https://github.com/elastic/elasticsearch/issues/121672 +- class: org.elasticsearch.index.mapper.extras.ScaledFloatFieldMapperTests + method: testBlockLoaderFromColumnReaderWithSyntheticSource + issue: https://github.com/elastic/elasticsearch/issues/123149 # Examples: # From 061c0ca15456601ce641f46a018511ecab98aa0f Mon Sep 17 00:00:00 2001 From: Patrick Doyle <810052+prdoyle@users.noreply.github.com> Date: Fri, 21 Feb 2025 10:23:22 -0500 Subject: [PATCH 12/27] Reinstate BYTE_SIZE_VALUE_ALWAYS_USES_BYTES (#122964) --- .../org/elasticsearch/TransportVersions.java | 3 + .../common/unit/ByteSizeValue.java | 14 +++-- .../common/unit/ByteSizeValueTests.java | 60 ++++++++++--------- 3 files changed, 44 insertions(+), 33 deletions(-) diff --git a/server/src/main/java/org/elasticsearch/TransportVersions.java b/server/src/main/java/org/elasticsearch/TransportVersions.java index 809d44ce13d9..1022dfc3b48f 100644 --- a/server/src/main/java/org/elasticsearch/TransportVersions.java +++ b/server/src/main/java/org/elasticsearch/TransportVersions.java @@ -187,6 +187,7 @@ public class TransportVersions { public static final TransportVersion REMOVE_DESIRED_NODE_VERSION_90 = def(9_000_0_03); public static final TransportVersion ESQL_DRIVER_TASK_DESCRIPTION_90 = def(9_000_0_04); public static final TransportVersion REMOVE_ALL_APPLICABLE_SELECTOR_9_0 = def(9_000_0_05); + public static final TransportVersion BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_90 = def(9_000_0_06); public static final TransportVersion COHERE_BIT_EMBEDDING_TYPE_SUPPORT_ADDED = def(9_001_0_00); public static final TransportVersion REMOVE_SNAPSHOT_FAILURES = def(9_002_0_00); public static final TransportVersion TRANSPORT_STATS_HANDLING_TIME_REQUIRED = def(9_003_0_00); @@ -201,6 +202,8 @@ public class TransportVersions { public static final TransportVersion REMOVE_REPOSITORY_CONFLICT_MESSAGE = def(9_012_0_00); public static final TransportVersion RERANKER_FAILURES_ALLOWED = def(9_013_0_00); public static final TransportVersion VOYAGE_AI_INTEGRATION_ADDED = def(9_014_0_00); + public static final TransportVersion BYTE_SIZE_VALUE_ALWAYS_USES_BYTES = def(9_015_0_00); + /* * STOP! READ THIS FIRST! No, really, * ____ _____ ___ ____ _ ____ _____ _ ____ _____ _ _ ___ ____ _____ ___ ____ ____ _____ _ diff --git a/server/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java b/server/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java index 23d76abdec2f..093b8ca33c6b 100644 --- a/server/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java +++ b/server/src/main/java/org/elasticsearch/common/unit/ByteSizeValue.java @@ -25,7 +25,9 @@ import java.math.RoundingMode; import java.util.Locale; import java.util.Objects; +import static org.elasticsearch.TransportVersions.BYTE_SIZE_VALUE_ALWAYS_USES_BYTES; import static org.elasticsearch.TransportVersions.BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_1; +import static org.elasticsearch.TransportVersions.BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_90; import static org.elasticsearch.TransportVersions.REVERT_BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_1; import static org.elasticsearch.common.unit.ByteSizeUnit.BYTES; import static org.elasticsearch.common.unit.ByteSizeUnit.GB; @@ -113,8 +115,7 @@ public class ByteSizeValue implements Writeable, Comparable, ToXC public static ByteSizeValue readFrom(StreamInput in) throws IOException { long size = in.readZLong(); ByteSizeUnit unit = ByteSizeUnit.readFrom(in); - TransportVersion tv = in.getTransportVersion(); - if (tv.onOrAfter(BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_1) && tv.before(REVERT_BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_1)) { + if (alwaysUseBytes(in.getTransportVersion())) { return newByteSizeValue(size, unit); } else { return of(size, unit); @@ -123,8 +124,7 @@ public class ByteSizeValue implements Writeable, Comparable, ToXC @Override public void writeTo(StreamOutput out) throws IOException { - TransportVersion tv = out.getTransportVersion(); - if (tv.onOrAfter(BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_1) && tv.before(REVERT_BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_1)) { + if (alwaysUseBytes(out.getTransportVersion())) { out.writeZLong(sizeInBytes); } else { out.writeZLong(Math.divideExact(sizeInBytes, desiredUnit.toBytes(1))); @@ -132,6 +132,12 @@ public class ByteSizeValue implements Writeable, Comparable, ToXC desiredUnit.writeTo(out); } + private static boolean alwaysUseBytes(TransportVersion tv) { + return tv.onOrAfter(BYTE_SIZE_VALUE_ALWAYS_USES_BYTES) + || tv.isPatchFrom(BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_90) + || tv.between(BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_1, REVERT_BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_1); + } + ByteSizeValue(long sizeInBytes, ByteSizeUnit desiredUnit) { this.sizeInBytes = sizeInBytes; this.desiredUnit = desiredUnit; diff --git a/server/src/test/java/org/elasticsearch/common/unit/ByteSizeValueTests.java b/server/src/test/java/org/elasticsearch/common/unit/ByteSizeValueTests.java index 79b06926cdef..3a27f3f8e867 100644 --- a/server/src/test/java/org/elasticsearch/common/unit/ByteSizeValueTests.java +++ b/server/src/test/java/org/elasticsearch/common/unit/ByteSizeValueTests.java @@ -11,7 +11,6 @@ package org.elasticsearch.common.unit; import org.elasticsearch.ElasticsearchParseException; import org.elasticsearch.TransportVersion; -import org.elasticsearch.TransportVersions; import org.elasticsearch.common.io.stream.BytesStreamOutput; import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.test.AbstractWireSerializingTestCase; @@ -22,6 +21,10 @@ import java.io.IOException; import java.util.List; import java.util.function.Function; +import static org.elasticsearch.TransportVersions.BYTE_SIZE_VALUE_ALWAYS_USES_BYTES; +import static org.elasticsearch.TransportVersions.BYTE_SIZE_VALUE_ALWAYS_USES_BYTES_90; +import static org.elasticsearch.TransportVersions.INITIAL_ELASTICSEARCH_9_0; +import static org.elasticsearch.TransportVersions.V_8_16_0; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; @@ -520,44 +523,43 @@ public class ByteSizeValueTests extends AbstractWireSerializingTestCase Date: Fri, 21 Feb 2025 11:45:08 -0500 Subject: [PATCH 13/27] Rename testTransportRoundTripsWithTwoDigitFractions (#123160) --- .../java/org/elasticsearch/common/unit/ByteSizeValueTests.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/test/java/org/elasticsearch/common/unit/ByteSizeValueTests.java b/server/src/test/java/org/elasticsearch/common/unit/ByteSizeValueTests.java index 3a27f3f8e867..6992cc580800 100644 --- a/server/src/test/java/org/elasticsearch/common/unit/ByteSizeValueTests.java +++ b/server/src/test/java/org/elasticsearch/common/unit/ByteSizeValueTests.java @@ -538,10 +538,11 @@ public class ByteSizeValueTests extends AbstractWireSerializingTestCase Date: Fri, 21 Feb 2025 12:27:12 -0500 Subject: [PATCH 14/27] [ML] Add ElasticInferenceServiceCompletionServiceSettings (#123155) Adding the missing NamedWriteable to the registry. --- docs/changelog/123155.yaml | 5 +++++ .../xpack/inference/InferenceNamedWriteablesProvider.java | 8 ++++++++ 2 files changed, 13 insertions(+) create mode 100644 docs/changelog/123155.yaml diff --git a/docs/changelog/123155.yaml b/docs/changelog/123155.yaml new file mode 100644 index 000000000000..73027c87510b --- /dev/null +++ b/docs/changelog/123155.yaml @@ -0,0 +1,5 @@ +pr: 123155 +summary: Add `ElasticInferenceServiceCompletionServiceSettings` +area: Machine Learning +type: bug +issues: [] diff --git a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceNamedWriteablesProvider.java b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceNamedWriteablesProvider.java index 35d2ce075c44..d57a6b86e4e7 100644 --- a/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceNamedWriteablesProvider.java +++ b/x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/InferenceNamedWriteablesProvider.java @@ -59,6 +59,7 @@ import org.elasticsearch.xpack.inference.services.cohere.embeddings.CohereEmbedd import org.elasticsearch.xpack.inference.services.cohere.rerank.CohereRerankServiceSettings; import org.elasticsearch.xpack.inference.services.cohere.rerank.CohereRerankTaskSettings; import org.elasticsearch.xpack.inference.services.elastic.ElasticInferenceServiceSparseEmbeddingsServiceSettings; +import org.elasticsearch.xpack.inference.services.elastic.completion.ElasticInferenceServiceCompletionServiceSettings; import org.elasticsearch.xpack.inference.services.elasticsearch.CustomElandInternalServiceSettings; import org.elasticsearch.xpack.inference.services.elasticsearch.CustomElandInternalTextEmbeddingServiceSettings; import org.elasticsearch.xpack.inference.services.elasticsearch.ElasticRerankerServiceSettings; @@ -654,5 +655,12 @@ public class InferenceNamedWriteablesProvider { ElasticInferenceServiceSparseEmbeddingsServiceSettings::new ) ); + namedWriteables.add( + new NamedWriteableRegistry.Entry( + ServiceSettings.class, + ElasticInferenceServiceCompletionServiceSettings.NAME, + ElasticInferenceServiceCompletionServiceSettings::new + ) + ); } } From af364a44ea35af006781b15053665cab8ada2942 Mon Sep 17 00:00:00 2001 From: Ruben van Staden Date: Fri, 21 Feb 2025 13:10:48 -0500 Subject: [PATCH 15/27] bump apm-data plugin version (#123166) --- x-pack/plugin/apm-data/src/main/resources/resources.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugin/apm-data/src/main/resources/resources.yaml b/x-pack/plugin/apm-data/src/main/resources/resources.yaml index 9484f577583e..beca2e5890bc 100644 --- a/x-pack/plugin/apm-data/src/main/resources/resources.yaml +++ b/x-pack/plugin/apm-data/src/main/resources/resources.yaml @@ -1,7 +1,7 @@ # "version" holds the version of the templates and ingest pipelines installed # by xpack-plugin apm-data. This must be increased whenever an existing template or # pipeline is changed, in order for it to be updated on Elasticsearch upgrade. -version: 12 +version: 13 component-templates: # Data lifecycle. From 2cc86b3df7ae7ad839569170b97497fa4da6e5bc Mon Sep 17 00:00:00 2001 From: Parker Timmins Date: Fri, 21 Feb 2025 13:17:26 -0600 Subject: [PATCH 16/27] Add read-block to source index during data stream reindex (#122887) When reindexing a data stream, we currently add a write block to the source indices so that new documents cannot be added to the index while it is being reindexed. A write block still allows the index to be deleted and for the metadata to be updated. It is possible that ILM could delete a backing index or update a backing index's lifecycle metadata while it is being reindexed. To avoid this, this PR sets a read-only block on the source index. This block must be removed before source index can be deleted after it is replaced with the destination index. --- ...indexDatastreamIndexTransportActionIT.java | 75 +++---------------- ...ReindexDataStreamIndexTransportAction.java | 48 ++++++++---- .../upgrades/DataStreamsUpgradeIT.java | 3 + 3 files changed, 46 insertions(+), 80 deletions(-) diff --git a/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java b/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java index bfb539a514e1..b67d12d095bf 100644 --- a/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java +++ b/x-pack/plugin/migrate/src/internalClusterTest/java/org/elasticsearch/xpack/migrate/action/ReindexDatastreamIndexTransportActionIT.java @@ -7,7 +7,6 @@ package org.elasticsearch.xpack.migrate.action; -import org.elasticsearch.ElasticsearchException; import org.elasticsearch.ResourceNotFoundException; import org.elasticsearch.action.DocWriteRequest; import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; @@ -16,7 +15,6 @@ import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; import org.elasticsearch.action.admin.indices.rollover.RolloverRequest; import org.elasticsearch.action.admin.indices.settings.get.GetSettingsRequest; -import org.elasticsearch.action.admin.indices.settings.get.GetSettingsResponse; import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest; import org.elasticsearch.action.admin.indices.template.delete.DeleteIndexTemplateRequest; import org.elasticsearch.action.admin.indices.template.delete.TransportDeleteIndexTemplateAction; @@ -30,11 +28,9 @@ import org.elasticsearch.action.ingest.PutPipelineRequest; import org.elasticsearch.action.ingest.PutPipelineTransportAction; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.action.support.master.AcknowledgedRequest; -import org.elasticsearch.cluster.block.ClusterBlockException; import org.elasticsearch.cluster.metadata.ComposableIndexTemplate; import org.elasticsearch.cluster.metadata.IndexMetadata; import org.elasticsearch.cluster.metadata.MappingMetadata; -import org.elasticsearch.cluster.metadata.MetadataIndexStateService; import org.elasticsearch.cluster.metadata.Template; import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.compress.CompressedXContent; @@ -82,7 +78,6 @@ import static org.elasticsearch.cluster.metadata.MetadataIndexTemplateService.DE import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertResponse; -import static org.elasticsearch.xcontent.XContentFactory.jsonBuilder; import static org.hamcrest.Matchers.equalTo; public class ReindexDatastreamIndexTransportActionIT extends ESIntegTestCase { @@ -274,8 +269,7 @@ public class ReindexDatastreamIndexTransportActionIT extends ESIntegTestCase { assertEquals(expectedDestIndexName, response.getDestIndex()); } - public void testDestIndexNameSet_withDotPrefix() throws Exception { - + public void testDestIndexNameSet_withDotPrefix() { var sourceIndex = "." + randomAlphaOfLength(20).toLowerCase(Locale.ROOT); safeGet(indicesAdmin().create(new CreateIndexRequest(sourceIndex))); @@ -288,13 +282,19 @@ public class ReindexDatastreamIndexTransportActionIT extends ESIntegTestCase { assertEquals(expectedDestIndexName, response.getDestIndex()); } - public void testDestIndexContainsDocs() throws Exception { + public void testDestIndexContainsDocs() { // source index with docs var numDocs = randomIntBetween(1, 100); var sourceIndex = randomAlphaOfLength(20).toLowerCase(Locale.ROOT); safeGet(indicesAdmin().create(new CreateIndexRequest(sourceIndex))); indexDocs(sourceIndex, numDocs); + var settings = Settings.builder() + .put(IndexMetadata.SETTING_BLOCKS_METADATA, randomBoolean()) + .put(IndexMetadata.SETTING_READ_ONLY, randomBoolean()) + .build(); + safeGet(indicesAdmin().updateSettings(new UpdateSettingsRequest(settings, sourceIndex))); + // call reindex var response = safeGet( client().execute(ReindexDataStreamIndexAction.INSTANCE, new ReindexDataStreamIndexAction.Request(sourceIndex)) @@ -305,31 +305,6 @@ public class ReindexDatastreamIndexTransportActionIT extends ESIntegTestCase { assertHitCount(prepareSearch(response.getDestIndex()).setSize(0), numDocs); } - public void testSetSourceToBlockWrites() throws Exception { - var settings = randomBoolean() ? Settings.builder().put(IndexMetadata.SETTING_BLOCKS_WRITE, true).build() : Settings.EMPTY; - - // empty source index - var sourceIndex = randomAlphaOfLength(20).toLowerCase(Locale.ROOT); - safeGet(indicesAdmin().create(new CreateIndexRequest(sourceIndex, settings))); - - // call reindex - safeGet(client().execute(ReindexDataStreamIndexAction.INSTANCE, new ReindexDataStreamIndexAction.Request(sourceIndex))); - - // Assert that source index is now read-only but not verified read-only - GetSettingsResponse getSettingsResponse = safeGet( - admin().indices().getSettings(new GetSettingsRequest(TEST_REQUEST_TIMEOUT).indices(sourceIndex)) - ); - assertTrue(parseBoolean(getSettingsResponse.getSetting(sourceIndex, IndexMetadata.SETTING_BLOCKS_WRITE))); - assertFalse( - parseBoolean(getSettingsResponse.getSetting(sourceIndex, MetadataIndexStateService.VERIFIED_READ_ONLY_SETTING.getKey())) - ); - - // assert that write to source fails - var indexReq = new IndexRequest(sourceIndex).source(jsonBuilder().startObject().field("field", "1").endObject()); - expectThrows(ClusterBlockException.class, client().index(indexReq)); - assertHitCount(prepareSearch(sourceIndex).setSize(0), 0); - } - public void testMissingSourceIndex() { var nonExistentSourceIndex = randomAlphaOfLength(20).toLowerCase(Locale.ROOT); expectThrows( @@ -387,34 +362,6 @@ public class ReindexDatastreamIndexTransportActionIT extends ESIntegTestCase { assertEquals("text", XContentMapValues.extractValue("properties.foo1.type", destMappings)); } - public void testFailIfMetadataBlockSet() { - var sourceIndex = randomAlphaOfLength(20).toLowerCase(Locale.ROOT); - var settings = Settings.builder().put(IndexMetadata.SETTING_BLOCKS_METADATA, true).build(); - safeGet(indicesAdmin().create(new CreateIndexRequest(sourceIndex, settings))); - - ElasticsearchException e = expectThrows( - ElasticsearchException.class, - client().execute(ReindexDataStreamIndexAction.INSTANCE, new ReindexDataStreamIndexAction.Request(sourceIndex)) - ); - assertTrue(e.getMessage().contains("Cannot reindex index") || e.getCause().getMessage().equals("Cannot reindex index")); - - cleanupMetadataBlocks(sourceIndex); - } - - public void testFailIfReadBlockSet() { - var sourceIndex = randomAlphaOfLength(20).toLowerCase(Locale.ROOT); - var settings = Settings.builder().put(IndexMetadata.SETTING_BLOCKS_READ, true).build(); - safeGet(indicesAdmin().create(new CreateIndexRequest(sourceIndex, settings))); - - ElasticsearchException e = expectThrows( - ElasticsearchException.class, - client().execute(ReindexDataStreamIndexAction.INSTANCE, new ReindexDataStreamIndexAction.Request(sourceIndex)) - ); - assertTrue(e.getMessage().contains("Cannot reindex index") || e.getCause().getMessage().equals("Cannot reindex index")); - - cleanupMetadataBlocks(sourceIndex); - } - public void testReadOnlyBlocksNotAddedBack() { var sourceIndex = randomAlphaOfLength(20).toLowerCase(Locale.ROOT); var settings = Settings.builder() @@ -434,7 +381,6 @@ public class ReindexDatastreamIndexTransportActionIT extends ESIntegTestCase { assertFalse(parseBoolean(settingsResponse.getSetting(destIndex, IndexMetadata.SETTING_READ_ONLY_ALLOW_DELETE))); assertFalse(parseBoolean(settingsResponse.getSetting(destIndex, IndexMetadata.SETTING_BLOCKS_WRITE))); - cleanupMetadataBlocks(sourceIndex); cleanupMetadataBlocks(destIndex); } @@ -752,9 +698,8 @@ public class ReindexDatastreamIndexTransportActionIT extends ESIntegTestCase { var settings = Settings.builder() .putNull(IndexMetadata.SETTING_READ_ONLY) .putNull(IndexMetadata.SETTING_READ_ONLY_ALLOW_DELETE) - .putNull(IndexMetadata.SETTING_BLOCKS_METADATA) - .build(); - safeGet(indicesAdmin().updateSettings(new UpdateSettingsRequest(settings, index))); + .putNull(IndexMetadata.SETTING_BLOCKS_METADATA); + updateIndexSettings(settings, index); } private static void indexDocs(String index, int numDocs) { diff --git a/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/ReindexDataStreamIndexTransportAction.java b/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/ReindexDataStreamIndexTransportAction.java index 2f20290d5804..7a5aaf459f5a 100644 --- a/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/ReindexDataStreamIndexTransportAction.java +++ b/x-pack/plugin/migrate/src/main/java/org/elasticsearch/xpack/migrate/action/ReindexDataStreamIndexTransportAction.java @@ -24,6 +24,7 @@ import org.elasticsearch.action.admin.indices.readonly.AddIndexBlockResponse; import org.elasticsearch.action.admin.indices.readonly.TransportAddIndexBlockAction; import org.elasticsearch.action.admin.indices.refresh.RefreshAction; import org.elasticsearch.action.admin.indices.refresh.RefreshRequest; +import org.elasticsearch.action.admin.indices.settings.put.TransportUpdateSettingsAction; import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest; import org.elasticsearch.action.bulk.BulkItemResponse; import org.elasticsearch.action.search.SearchRequest; @@ -55,11 +56,13 @@ import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.deprecation.DeprecatedIndexPredicate; import org.elasticsearch.xpack.migrate.MigrateTemplateRegistry; +import java.util.Arrays; import java.util.Locale; import java.util.Map; import java.util.Objects; -import static org.elasticsearch.cluster.metadata.IndexMetadata.APIBlock.WRITE; +import static org.elasticsearch.cluster.metadata.IndexMetadata.APIBlock.METADATA; +import static org.elasticsearch.cluster.metadata.IndexMetadata.APIBlock.READ_ONLY; public class ReindexDataStreamIndexTransportAction extends HandledTransportAction< ReindexDataStreamIndexAction.Request, @@ -145,19 +148,10 @@ public class ReindexDataStreamIndexTransportAction extends HandledTransportActio ); } - if (settingsBefore.getAsBoolean(IndexMetadata.SETTING_BLOCKS_READ, false)) { - var errorMessage = String.format(Locale.ROOT, "Cannot reindex index [%s] which has a read block.", destIndexName); - listener.onFailure(new ElasticsearchException(errorMessage)); - return; - } - if (settingsBefore.getAsBoolean(IndexMetadata.SETTING_BLOCKS_METADATA, false)) { - var errorMessage = String.format(Locale.ROOT, "Cannot reindex index [%s] which has a metadata block.", destIndexName); - listener.onFailure(new ElasticsearchException(errorMessage)); - return; - } final boolean wasClosed = isClosed(sourceIndex); - SubscribableListener.newForked(l -> setBlockWrites(sourceIndexName, l, taskId)) + SubscribableListener.newForked(l -> removeMetadataBlocks(sourceIndexName, taskId, l)) .andThen(l -> openIndexIfClosed(sourceIndexName, wasClosed, l, taskId)) + .andThen(l -> setReadOnly(sourceIndexName, l, taskId)) .andThen(l -> refresh(sourceIndexName, l, taskId)) .andThen(l -> deleteDestIfExists(destIndexName, l, taskId)) .andThen(l -> createIndex(sourceIndex, destIndexName, l, taskId)) @@ -166,6 +160,7 @@ public class ReindexDataStreamIndexTransportAction extends HandledTransportActio .andThen(l -> copyIndexMetadataToDest(sourceIndexName, destIndexName, l, taskId)) .andThen(l -> sanityCheck(sourceIndexName, destIndexName, l, taskId)) .andThen(l -> closeIndexIfWasClosed(destIndexName, wasClosed, l, taskId)) + .andThen(l -> removeAPIBlocks(sourceIndexName, taskId, l, READ_ONLY)) .andThenApply(ignored -> new ReindexDataStreamIndexAction.Response(destIndexName)) .addListener(listener); } @@ -201,9 +196,9 @@ public class ReindexDataStreamIndexTransportAction extends HandledTransportActio return indexMetadata.getState().equals(IndexMetadata.State.CLOSE); } - private void setBlockWrites(String sourceIndexName, ActionListener listener, TaskId parentTaskId) { - logger.debug("Setting write block on source index [{}]", sourceIndexName); - addBlockToIndex(WRITE, sourceIndexName, new ActionListener<>() { + private void setReadOnly(String sourceIndexName, ActionListener listener, TaskId parentTaskId) { + logger.debug("Setting read-only on source index [{}]", sourceIndexName); + addBlockToIndex(READ_ONLY, sourceIndexName, new ActionListener<>() { @Override public void onResponse(AddIndexBlockResponse response) { if (response.isAcknowledged()) { @@ -399,6 +394,29 @@ public class ReindexDataStreamIndexTransportAction extends HandledTransportActio client.admin().indices().execute(TransportAddIndexBlockAction.TYPE, addIndexBlockRequest, listener); } + /** + * All metadata blocks need to be removed at the start for the following reasons: + * 1) If the source index has a metadata only block, the read-only block can't be added. + * 2) If the source index is read-only and closed, it can't be opened. + */ + private void removeMetadataBlocks(String indexName, TaskId parentTaskId, ActionListener listener) { + logger.debug("Removing metadata blocks from index [{}]", indexName); + removeAPIBlocks(indexName, parentTaskId, listener, METADATA, READ_ONLY); + } + + private void removeAPIBlocks( + String indexName, + TaskId parentTaskId, + ActionListener listener, + IndexMetadata.APIBlock... blocks + ) { + Settings.Builder settings = Settings.builder(); + Arrays.stream(blocks).forEach(b -> settings.putNull(b.settingName())); + var updateSettingsRequest = new UpdateSettingsRequest(settings.build(), indexName); + updateSettingsRequest.setParentTask(parentTaskId); + client.execute(TransportUpdateSettingsAction.TYPE, updateSettingsRequest, listener); + } + private void getIndexDocCount(String index, TaskId parentTaskId, ActionListener listener) { SearchRequest countRequest = new SearchRequest(index); SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder().size(0).trackTotalHits(true); diff --git a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java index 1d320f97a41a..77ab71b5db6e 100644 --- a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java +++ b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java @@ -548,6 +548,9 @@ public class DataStreamsUpgradeIT extends AbstractUpgradeTestCase { if (randomBoolean()) { closeIndex(oldIndexName); } + if (randomBoolean()) { + assertOK(client().performRequest(new Request("PUT", oldIndexName + "/_block/read_only"))); + } } Request reindexRequest = new Request("POST", "/_migration/reindex"); reindexRequest.setJsonEntity(Strings.format(""" From 73269285023881459eb6ce2d229f456ea30094b8 Mon Sep 17 00:00:00 2001 From: kanoshiou <73424326+kanoshiou@users.noreply.github.com> Date: Sat, 22 Feb 2025 03:34:46 +0800 Subject: [PATCH 17/27] Fix failed ScaledFloatFieldMapperTests (#123144) --- .../extras/ScaledFloatFieldMapperTests.java | 30 ++++--------------- muted-tests.yml | 9 ------ 2 files changed, 5 insertions(+), 34 deletions(-) diff --git a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapperTests.java b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapperTests.java index 83fe07170d6e..1f1430d70c69 100644 --- a/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapperTests.java +++ b/modules/mapper-extras/src/test/java/org/elasticsearch/index/mapper/extras/ScaledFloatFieldMapperTests.java @@ -31,7 +31,6 @@ import org.elasticsearch.test.ESTestCase; import org.elasticsearch.xcontent.XContentBuilder; import org.elasticsearch.xcontent.XContentFactory; import org.elasticsearch.xcontent.XContentType; -import org.hamcrest.Matcher; import org.junit.AssumptionViolatedException; import java.io.IOException; @@ -39,7 +38,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; -import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Stream; @@ -48,7 +46,6 @@ import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.notANumber; public class ScaledFloatFieldMapperTests extends NumberFieldMapperTests { @@ -382,7 +379,7 @@ public class ScaledFloatFieldMapperTests extends NumberFieldMapperTests { if (randomBoolean()) { Value v = generateValue(); if (v.malformedOutput == null) { - return new SyntheticSourceExample(v.input, v.output, roundDocValues(v.output), this::mapping); + return new SyntheticSourceExample(v.input, v.output, this::mapping); } return new SyntheticSourceExample(v.input, v.malformedOutput, null, this::mapping); } @@ -396,9 +393,7 @@ public class ScaledFloatFieldMapperTests extends NumberFieldMapperTests { List outList = Stream.concat(outputFromDocValues.stream(), malformedOutput).toList(); Object out = outList.size() == 1 ? outList.get(0) : outList; - List outBlockList = outputFromDocValues.stream().map(this::roundDocValues).sorted().toList(); - Object outBlock = outBlockList.size() == 1 ? outBlockList.get(0) : outBlockList; - return new SyntheticSourceExample(in, out, outBlock, this::mapping); + return new SyntheticSourceExample(in, out, this::mapping); } private record Value(Object input, Double output, Object malformedOutput) {} @@ -442,16 +437,6 @@ public class ScaledFloatFieldMapperTests extends NumberFieldMapperTests { return decoded; } - private double roundDocValues(double d) { - // Special case due to rounding, see implementation. - if (Math.abs(d) == Double.MAX_VALUE) { - return d; - } - - long encoded = Math.round(d * scalingFactor); - return encoded * (1 / scalingFactor); - } - private void mapping(XContentBuilder b) throws IOException { b.field("type", "scaled_float"); b.field("scaling_factor", scalingFactor); @@ -475,14 +460,9 @@ public class ScaledFloatFieldMapperTests extends NumberFieldMapperTests { } } - @Override - protected Function loadBlockExpected() { - return v -> (Number) v; - } - - @Override - protected Matcher blockItemMatcher(Object expected) { - return "NaN".equals(expected) ? notANumber() : equalTo(expected); + protected BlockReaderSupport getSupportedReaders(MapperService mapper, String loaderFieldName) { + assumeTrue("Disabled, tested by ScaledFloatFieldBlockLoaderTests instead", false); + return null; } @Override diff --git a/muted-tests.yml b/muted-tests.yml index 3344b6e4335b..9cb8eab0dd5d 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -332,18 +332,9 @@ tests: - class: org.elasticsearch.xpack.esql.action.CrossClusterQueryWithPartialResultsIT method: testPartialResults issue: https://github.com/elastic/elasticsearch/issues/123101 -- class: org.elasticsearch.index.mapper.extras.ScaledFloatFieldMapperTests - method: testBlockLoaderFromRowStrideReader - issue: https://github.com/elastic/elasticsearch/issues/123126 -- class: org.elasticsearch.index.mapper.extras.ScaledFloatFieldMapperTests - method: testBlockLoaderFromRowStrideReaderWithSyntheticSource - issue: https://github.com/elastic/elasticsearch/issues/123145 - class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT method: testStopQueryLocal issue: https://github.com/elastic/elasticsearch/issues/121672 -- class: org.elasticsearch.index.mapper.extras.ScaledFloatFieldMapperTests - method: testBlockLoaderFromColumnReaderWithSyntheticSource - issue: https://github.com/elastic/elasticsearch/issues/123149 # Examples: # From 2bda4c1fa8a6cff25ead5596824651d8a3916c4a Mon Sep 17 00:00:00 2001 From: Alexey Ivanov Date: Fri, 21 Feb 2025 19:50:57 +0000 Subject: [PATCH 18/27] Converting an Existing Data Stream to a System DataStream is Broken (#121392) Adds support of converting existing data stream to a system data stream as part of existing system_index_metadata_upgrade_service task --- docs/changelog/121392.yaml | 5 + .../cluster/metadata/DataStream.java | 19 +- .../SystemIndexMetadataUpgradeService.java | 308 +++++++++++++----- .../indices/SystemDataStreamDescriptor.java | 15 +- ...ystemIndexMetadataUpgradeServiceTests.java | 119 ++++++- 5 files changed, 358 insertions(+), 108 deletions(-) create mode 100644 docs/changelog/121392.yaml diff --git a/docs/changelog/121392.yaml b/docs/changelog/121392.yaml new file mode 100644 index 000000000000..6323789f071d --- /dev/null +++ b/docs/changelog/121392.yaml @@ -0,0 +1,5 @@ +pr: 121392 +summary: Include data streams when converting an existing resource to a system resource +area: Infra/Core +type: bug +issues: [] diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/DataStream.java b/server/src/main/java/org/elasticsearch/cluster/metadata/DataStream.java index 1313060936f6..ced580717c2f 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/DataStream.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/DataStream.java @@ -301,6 +301,13 @@ public final class DataStream implements SimpleDiffable, ToXContentO return failureIndices.containsIndex(indexName); } + /** + * Returns true if the index name provided belongs to this data stream. + */ + public boolean containsIndex(String indexName) { + return backingIndices.containsIndex(indexName) || failureIndices.containsIndex(indexName); + } + public DataStreamOptions getDataStreamOptions() { return dataStreamOptions; } @@ -782,8 +789,9 @@ public final class DataStream implements SimpleDiffable, ToXContentO // ensure that no aliases reference index ensureNoAliasesOnIndex(clusterMetadata, index); - List backingIndices = new ArrayList<>(this.backingIndices.indices); - backingIndices.add(0, index); + List backingIndices = new ArrayList<>(this.backingIndices.indices.size() + 1); + backingIndices.add(index); + backingIndices.addAll(this.backingIndices.indices); assert backingIndices.size() == this.backingIndices.indices.size() + 1; return copy().setBackingIndices(this.backingIndices.copy().setIndices(backingIndices).build()) .setGeneration(generation + 1) @@ -808,8 +816,9 @@ public final class DataStream implements SimpleDiffable, ToXContentO ensureNoAliasesOnIndex(clusterMetadata, index); - List updatedFailureIndices = new ArrayList<>(failureIndices.indices); - updatedFailureIndices.add(0, index); + List updatedFailureIndices = new ArrayList<>(failureIndices.indices.size() + 1); + updatedFailureIndices.add(index); + updatedFailureIndices.addAll(failureIndices.indices); assert updatedFailureIndices.size() == failureIndices.indices.size() + 1; return copy().setFailureIndices(failureIndices.copy().setIndices(updatedFailureIndices).build()) .setGeneration(generation + 1) @@ -1039,7 +1048,7 @@ public final class DataStream implements SimpleDiffable, ToXContentO * we return false. */ public boolean isIndexManagedByDataStreamLifecycle(Index index, Function indexMetadataSupplier) { - if (backingIndices.containsIndex(index.getName()) == false && failureIndices.containsIndex(index.getName()) == false) { + if (containsIndex(index.getName()) == false) { return false; } IndexMetadata indexMetadata = indexMetadataSupplier.apply(index.getName()); diff --git a/server/src/main/java/org/elasticsearch/cluster/metadata/SystemIndexMetadataUpgradeService.java b/server/src/main/java/org/elasticsearch/cluster/metadata/SystemIndexMetadataUpgradeService.java index 228bb3b222a5..a79923921d37 100644 --- a/server/src/main/java/org/elasticsearch/cluster/metadata/SystemIndexMetadataUpgradeService.java +++ b/server/src/main/java/org/elasticsearch/cluster/metadata/SystemIndexMetadataUpgradeService.java @@ -14,18 +14,28 @@ import org.apache.logging.log4j.Logger; import org.elasticsearch.cluster.ClusterChangedEvent; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.ClusterStateListener; -import org.elasticsearch.cluster.ClusterStateUpdateTask; +import org.elasticsearch.cluster.ClusterStateTaskExecutor; +import org.elasticsearch.cluster.ClusterStateTaskListener; import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.cluster.service.MasterServiceTaskQueue; +import org.elasticsearch.common.Priority; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.concurrent.AbstractRunnable; -import org.elasticsearch.core.SuppressForbidden; +import org.elasticsearch.index.Index; import org.elasticsearch.indices.SystemIndexMappingUpdateService; import org.elasticsearch.indices.SystemIndices; import org.elasticsearch.threadpool.ThreadPool; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * A service responsible for updating the metadata used by system indices. @@ -38,47 +48,61 @@ public class SystemIndexMetadataUpgradeService implements ClusterStateListener { private final SystemIndices systemIndices; private final ClusterService clusterService; - - private volatile boolean updateTaskPending = false; - - private volatile long triggeredVersion = -1L; + private final MasterServiceTaskQueue taskQueue; public SystemIndexMetadataUpgradeService(SystemIndices systemIndices, ClusterService clusterService) { this.systemIndices = systemIndices; this.clusterService = clusterService; + this.taskQueue = clusterService.createTaskQueue( + "system-indices-metadata-upgrade", + Priority.NORMAL, + new SystemIndexMetadataUpgradeExecutor() + ); } @Override public void clusterChanged(ClusterChangedEvent event) { - if (updateTaskPending == false - && event.localNodeMaster() + Metadata currentMetadata = event.state().metadata(); + Metadata previousMetadata = event.previousState().metadata(); + if (event.localNodeMaster() && (event.previousState().nodes().isLocalNodeElectedMaster() == false - || event.state().metadata().indices() != event.previousState().metadata().indices())) { - final Map indexMetadataMap = event.state().metadata().indices(); - final var previousIndices = event.previousState().metadata().indices(); - final long triggerV = event.state().version(); - triggeredVersion = triggerV; + || currentMetadata.indices() != previousMetadata.indices() + || currentMetadata.dataStreams() != previousMetadata.dataStreams())) { + final Map indexMetadataMap = currentMetadata.indices(); + final var previousIndices = previousMetadata.indices(); + Map dataStreams = currentMetadata.dataStreams(); + Map previousDataStreams = previousMetadata.dataStreams(); // Fork to the management pool to avoid blocking the cluster applier thread unnecessarily for very large index counts // TODO: we should have a more efficient way of getting just the changed indices so that we don't have to fork here clusterService.threadPool().executor(ThreadPool.Names.MANAGEMENT).execute(new AbstractRunnable() { @Override protected void doRun() { - if (triggeredVersion != triggerV) { - // don't run if another newer check task was triggered already - return; - } - for (Map.Entry cursor : indexMetadataMap.entrySet()) { - if (cursor.getValue() != previousIndices.get(cursor.getKey())) { - IndexMetadata indexMetadata = cursor.getValue(); - if (requiresUpdate(indexMetadata)) { - updateTaskPending = true; - submitUnbatchedTask( - "system_index_metadata_upgrade_service {system metadata change}", - new SystemIndexMetadataUpdateTask() - ); - break; + Collection changedDataStreams = new ArrayList<>(); + Set dataStreamIndices = new HashSet<>(); + for (Map.Entry cursor : dataStreams.entrySet()) { + DataStream dataStream = cursor.getValue(); + if (dataStream != previousDataStreams.get(cursor.getKey())) { + if (requiresUpdate(dataStream)) { + changedDataStreams.add(dataStream); } } + + getIndicesBackingDataStream(dataStream).forEach(dataStreamIndices::add); + } + + Collection changedIndices = new ArrayList<>(); + for (Map.Entry cursor : indexMetadataMap.entrySet()) { + IndexMetadata indexMetadata = cursor.getValue(); + Index index = indexMetadata.getIndex(); + if (cursor.getValue() != previousIndices.get(cursor.getKey()) && dataStreamIndices.contains(index) == false) { + if (requiresUpdate(indexMetadata)) { + changedIndices.add(index); + } + } + } + + if (changedIndices.isEmpty() == false || changedDataStreams.isEmpty() == false) { + submitUpdateTask(changedIndices, changedDataStreams); } } @@ -91,6 +115,12 @@ public class SystemIndexMetadataUpgradeService implements ClusterStateListener { } } + // visible for testing + void submitUpdateTask(Collection changedIndices, Collection changedDataStreams) { + SystemIndexMetadataUpgradeTask task = new SystemIndexMetadataUpgradeTask(changedIndices, changedDataStreams); + taskQueue.submitTask("system-index-metadata-upgrade-service", task, null); + } + // package-private for testing boolean requiresUpdate(IndexMetadata indexMetadata) { final boolean shouldBeSystem = shouldBeSystem(indexMetadata); @@ -107,6 +137,30 @@ public class SystemIndexMetadataUpgradeService implements ClusterStateListener { return false; } + // package-private for testing + boolean requiresUpdate(DataStream dataStream) { + final boolean shouldBeSystem = shouldBeSystem(dataStream); + + // should toggle system index status + if (shouldBeSystem != dataStream.isSystem()) { + return true; + } + + if (shouldBeSystem) { + return dataStream.isHidden() == false; + } + + return false; + } + + private boolean shouldBeSystem(DataStream dataStream) { + return systemIndices.isSystemDataStream(dataStream.getName()); + } + + private static Stream getIndicesBackingDataStream(DataStream dataStream) { + return Stream.concat(dataStream.getIndices().stream(), dataStream.getFailureIndices().stream()); + } + // package-private for testing static boolean isVisible(IndexMetadata indexMetadata) { return indexMetadata.getSettings().getAsBoolean(IndexMetadata.SETTING_INDEX_HIDDEN, false) == false; @@ -114,8 +168,7 @@ public class SystemIndexMetadataUpgradeService implements ClusterStateListener { // package-private for testing boolean shouldBeSystem(IndexMetadata indexMetadata) { - return systemIndices.isSystemIndex(indexMetadata.getIndex()) - || systemIndices.isSystemIndexBackingDataStream(indexMetadata.getIndex().getName()); + return systemIndices.isSystemIndex(indexMetadata.getIndex()); } // package-private for testing @@ -123,73 +176,148 @@ public class SystemIndexMetadataUpgradeService implements ClusterStateListener { return indexMetadata.getAliases().values().stream().anyMatch(a -> Boolean.FALSE.equals(a.isHidden())); } - @SuppressForbidden(reason = "legacy usage of unbatched task") // TODO add support for batching here - private void submitUnbatchedTask(@SuppressWarnings("SameParameterValue") String source, ClusterStateUpdateTask task) { - clusterService.submitUnbatchedStateUpdateTask(source, task); - } - - // visible for testing - SystemIndexMetadataUpdateTask getTask() { - return new SystemIndexMetadataUpdateTask(); - } - - public class SystemIndexMetadataUpdateTask extends ClusterStateUpdateTask { - - @Override - public ClusterState execute(ClusterState currentState) throws Exception { - final Map indexMetadataMap = currentState.metadata().indices(); - final List updatedMetadata = new ArrayList<>(); - for (Map.Entry entry : indexMetadataMap.entrySet()) { - final IndexMetadata indexMetadata = entry.getValue(); - final boolean shouldBeSystem = shouldBeSystem(indexMetadata); - IndexMetadata.Builder builder = IndexMetadata.builder(indexMetadata); - boolean updated = false; - if (shouldBeSystem != indexMetadata.isSystem()) { - builder.system(indexMetadata.isSystem() == false); - updated = true; - } - if (shouldBeSystem && isVisible(indexMetadata)) { - builder.settings(Settings.builder().put(indexMetadata.getSettings()).put(IndexMetadata.SETTING_INDEX_HIDDEN, true)); - builder.settingsVersion(builder.settingsVersion() + 1); - updated = true; - } - if (shouldBeSystem && hasVisibleAlias(indexMetadata)) { - for (AliasMetadata aliasMetadata : indexMetadata.getAliases().values()) { - if (Boolean.FALSE.equals(aliasMetadata.isHidden())) { - builder.removeAlias(aliasMetadata.alias()); - builder.putAlias( - AliasMetadata.builder(aliasMetadata.alias()) - .filter(aliasMetadata.filter()) - .indexRouting(aliasMetadata.indexRouting()) - .isHidden(true) - .searchRouting(aliasMetadata.searchRouting()) - .writeIndex(aliasMetadata.writeIndex()) - ); - } - } - } - if (updated) { - updatedMetadata.add(builder.build()); - } - } - - if (updatedMetadata.isEmpty() == false) { - final Metadata.Builder builder = Metadata.builder(currentState.metadata()); - updatedMetadata.forEach(idxMeta -> builder.put(idxMeta, true)); - return ClusterState.builder(currentState).metadata(builder).build(); - } - return currentState; - } + private record SystemIndexMetadataUpgradeTask(Collection changedIndices, Collection changedDataStreams) + implements + ClusterStateTaskListener { @Override public void onFailure(Exception e) { - updateTaskPending = false; - logger.error("failed to update system index metadata", e); + logger.error("System index metadata upgrade failed", e); } @Override - public void clusterStateProcessed(ClusterState oldState, ClusterState newState) { - updateTaskPending = false; + public String toString() { + return "SystemIndexMetadataUpgradeTask[changedIndices=" + + changedIndices.stream().map(Index::getName).collect(Collectors.joining(",")) + + ";changedDataStreams=" + + changedDataStreams.stream().map(DataStream::getName).collect(Collectors.joining(",")) + + "]"; + } + } + + private class SystemIndexMetadataUpgradeExecutor implements ClusterStateTaskExecutor { + @Override + public ClusterState execute(BatchExecutionContext batchExecutionContext) { + ClusterState initialState = batchExecutionContext.initialState(); + + List> taskContexts = batchExecutionContext.taskContexts(); + List indices = taskContexts.stream() + .map(TaskContext::getTask) + .map(SystemIndexMetadataUpgradeTask::changedIndices) + .flatMap(Collection::stream) + .toList(); + List updatedMetadata = updateIndices(initialState, indices); + + List dataStreams = taskContexts.stream() + .map(TaskContext::getTask) + .map(SystemIndexMetadataUpgradeTask::changedDataStreams) + .flatMap(Collection::stream) + .toList(); + List updatedDataStreams = updateDataStreams(dataStreams); + List updatedBackingIndices = updateIndicesBackingDataStreams(initialState, updatedDataStreams); + + for (TaskContext taskContext : taskContexts) { + taskContext.success(() -> {}); + } + + if (updatedMetadata.isEmpty() == false || updatedDataStreams.isEmpty() == false) { + Metadata.Builder builder = Metadata.builder(initialState.metadata()); + updatedMetadata.forEach(idxMeta -> builder.put(idxMeta, true)); + updatedDataStreams.forEach(builder::put); + updatedBackingIndices.forEach(idxMeta -> builder.put(idxMeta, true)); + + return ClusterState.builder(initialState).metadata(builder).build(); + } + return initialState; + } + + private List updateIndices(ClusterState currentState, List indices) { + if (indices.isEmpty()) { + return Collections.emptyList(); + } + Metadata metadata = currentState.metadata(); + final List updatedMetadata = new ArrayList<>(); + for (Index index : indices) { + IndexMetadata indexMetadata = metadata.index(index); + final boolean shouldBeSystem = shouldBeSystem(indexMetadata); + IndexMetadata updatedIndexMetadata = updateIndexIfNecessary(indexMetadata, shouldBeSystem); + if (updatedIndexMetadata != null) { + updatedMetadata.add(updatedIndexMetadata); + } + } + return updatedMetadata; + } + + private IndexMetadata updateIndexIfNecessary(IndexMetadata indexMetadata, boolean shouldBeSystem) { + IndexMetadata.Builder builder = IndexMetadata.builder(indexMetadata); + boolean updated = false; + if (shouldBeSystem != indexMetadata.isSystem()) { + builder.system(indexMetadata.isSystem() == false); + updated = true; + } + if (shouldBeSystem && isVisible(indexMetadata)) { + builder.settings(Settings.builder().put(indexMetadata.getSettings()).put(IndexMetadata.SETTING_INDEX_HIDDEN, true)); + builder.settingsVersion(builder.settingsVersion() + 1); + updated = true; + } + if (shouldBeSystem && hasVisibleAlias(indexMetadata)) { + for (AliasMetadata aliasMetadata : indexMetadata.getAliases().values()) { + if (Boolean.FALSE.equals(aliasMetadata.isHidden())) { + builder.removeAlias(aliasMetadata.alias()); + builder.putAlias( + AliasMetadata.builder(aliasMetadata.alias()) + .filter(aliasMetadata.filter()) + .indexRouting(aliasMetadata.indexRouting()) + .isHidden(true) + .searchRouting(aliasMetadata.searchRouting()) + .writeIndex(aliasMetadata.writeIndex()) + ); + updated = true; + } + } + } + return updated ? builder.build() : null; + } + + private List updateDataStreams(List dataStreams) { + if (dataStreams.isEmpty()) { + return Collections.emptyList(); + } + List updatedDataStreams = new ArrayList<>(); + for (DataStream dataStream : dataStreams) { + boolean shouldBeSystem = shouldBeSystem(dataStream); + if (dataStream.isSystem() != shouldBeSystem) { + DataStream.Builder dataStreamBuilder = dataStream.copy().setSystem(shouldBeSystem); + if (shouldBeSystem) { + dataStreamBuilder.setHidden(true); + } + + updatedDataStreams.add(dataStreamBuilder.build()); + } + } + return updatedDataStreams; + } + + private List updateIndicesBackingDataStreams(ClusterState currentState, List updatedDataStreams) { + if (updatedDataStreams.isEmpty()) { + return Collections.emptyList(); + } + Metadata metadata = currentState.metadata(); + final List updatedMetadata = new ArrayList<>(); + + for (DataStream updatedDataStream : updatedDataStreams) { + boolean shouldBeSystem = updatedDataStream.isSystem(); + List updatedIndicesMetadata = getIndicesBackingDataStreamMetadata(metadata, updatedDataStream).map( + idx -> updateIndexIfNecessary(idx, shouldBeSystem) + ).filter(Objects::nonNull).toList(); + + updatedMetadata.addAll(updatedIndicesMetadata); + } + return updatedMetadata; + } + + private Stream getIndicesBackingDataStreamMetadata(Metadata metadata, DataStream dataStream) { + return getIndicesBackingDataStream(dataStream).map(metadata::index); } } } diff --git a/server/src/main/java/org/elasticsearch/indices/SystemDataStreamDescriptor.java b/server/src/main/java/org/elasticsearch/indices/SystemDataStreamDescriptor.java index 9a78556f9239..349e21af98b9 100644 --- a/server/src/main/java/org/elasticsearch/indices/SystemDataStreamDescriptor.java +++ b/server/src/main/java/org/elasticsearch/indices/SystemDataStreamDescriptor.java @@ -9,17 +9,17 @@ package org.elasticsearch.indices; -import org.apache.lucene.util.automaton.CharacterRunAutomaton; import org.elasticsearch.cluster.metadata.ComponentTemplate; import org.elasticsearch.cluster.metadata.ComposableIndexTemplate; import org.elasticsearch.cluster.metadata.DataStream; import org.elasticsearch.cluster.metadata.Metadata; +import org.elasticsearch.index.Index; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; - -import static org.elasticsearch.indices.AssociatedIndexDescriptor.buildAutomaton; +import java.util.stream.Stream; /** * Describes a {@link DataStream} that is reserved for use by a system feature. @@ -53,7 +53,6 @@ public class SystemDataStreamDescriptor { private final Map componentTemplates; private final List allowedElasticProductOrigins; private final ExecutorNames executorNames; - private final CharacterRunAutomaton characterRunAutomaton; /** * Creates a new descriptor for a system data descriptor @@ -96,8 +95,6 @@ public class SystemDataStreamDescriptor { throw new IllegalArgumentException("External system data stream without allowed products is not a valid combination"); } this.executorNames = Objects.nonNull(executorNames) ? executorNames : ExecutorNames.DEFAULT_SYSTEM_DATA_STREAM_THREAD_POOLS; - - this.characterRunAutomaton = new CharacterRunAutomaton(buildAutomaton(backingIndexPatternForDataStream(this.dataStreamName))); } public String getDataStreamName() { @@ -110,7 +107,11 @@ public class SystemDataStreamDescriptor { * @return List of names of backing indices */ public List getBackingIndexNames(Metadata metadata) { - return metadata.indices().keySet().stream().filter(this.characterRunAutomaton::run).toList(); + DataStream dataStream = metadata.dataStreams().get(dataStreamName); + if (dataStream == null) { + return Collections.emptyList(); + } + return Stream.concat(dataStream.getIndices().stream(), dataStream.getFailureIndices().stream()).map(Index::getName).toList(); } public String getDescription() { diff --git a/server/src/test/java/org/elasticsearch/cluster/metadata/SystemIndexMetadataUpgradeServiceTests.java b/server/src/test/java/org/elasticsearch/cluster/metadata/SystemIndexMetadataUpgradeServiceTests.java index 0dcea706e7f9..f19cfce264d2 100644 --- a/server/src/test/java/org/elasticsearch/cluster/metadata/SystemIndexMetadataUpgradeServiceTests.java +++ b/server/src/test/java/org/elasticsearch/cluster/metadata/SystemIndexMetadataUpgradeServiceTests.java @@ -11,20 +11,32 @@ package org.elasticsearch.cluster.metadata; import org.elasticsearch.cluster.ClusterName; import org.elasticsearch.cluster.ClusterState; +import org.elasticsearch.cluster.ClusterStateTaskExecutor; +import org.elasticsearch.cluster.ClusterStateTaskListener; import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.cluster.service.ClusterStateTaskExecutorUtils; +import org.elasticsearch.cluster.service.MasterServiceTaskQueue; +import org.elasticsearch.common.Priority; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.IndexVersion; +import org.elasticsearch.indices.ExecutorNames; +import org.elasticsearch.indices.SystemDataStreamDescriptor; import org.elasticsearch.indices.SystemIndexDescriptor; import org.elasticsearch.indices.SystemIndices; import org.elasticsearch.test.ESTestCase; import org.junit.Before; +import java.util.Collections; import java.util.List; import java.util.Locale; import java.util.Map; import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class SystemIndexMetadataUpgradeServiceTests extends ESTestCase { @@ -49,17 +61,62 @@ public class SystemIndexMetadataUpgradeServiceTests extends ESTestCase { .setOrigin("FAKE_ORIGIN") .build(); - private SystemIndexMetadataUpgradeService service; + private static final String SYSTEM_DATA_STREAM_NAME = ".my-ds"; + private static final String SYSTEM_DATA_STREAM_INDEX_NAME = DataStream.BACKING_INDEX_PREFIX + SYSTEM_DATA_STREAM_NAME + "-1"; + private static final String SYSTEM_DATA_STREAM_FAILSTORE_NAME = DataStream.FAILURE_STORE_PREFIX + SYSTEM_DATA_STREAM_NAME; + private static final SystemDataStreamDescriptor SYSTEM_DATA_STREAM_DESCRIPTOR = new SystemDataStreamDescriptor( + SYSTEM_DATA_STREAM_NAME, + "System datastream for test", + SystemDataStreamDescriptor.Type.INTERNAL, + ComposableIndexTemplate.builder().build(), + Collections.emptyMap(), + Collections.singletonList("FAKE_ORIGIN"), + ExecutorNames.DEFAULT_SYSTEM_DATA_STREAM_THREAD_POOLS + ); + private SystemIndexMetadataUpgradeService service; + private ClusterStateTaskListener task; + private ClusterStateTaskExecutor executor; + + @SuppressWarnings("unchecked") @Before public void setUpTest() { // set up a system index upgrade service + ClusterService clusterService = mock(ClusterService.class); + MasterServiceTaskQueue queue = mock(MasterServiceTaskQueue.class); + when(clusterService.createTaskQueue(eq("system-indices-metadata-upgrade"), eq(Priority.NORMAL), any())).thenAnswer(invocation -> { + executor = invocation.getArgument(2, ClusterStateTaskExecutor.class); + return queue; + }); + doAnswer(invocation -> { + task = invocation.getArgument(1, ClusterStateTaskListener.class); + return null; + }).when(queue).submitTask(any(), any(), any()); + this.service = new SystemIndexMetadataUpgradeService( - new SystemIndices(List.of(new SystemIndices.Feature("foo", "a test feature", List.of(DESCRIPTOR)))), - mock(ClusterService.class) + new SystemIndices( + List.of( + new SystemIndices.Feature("foo", "a test feature", List.of(DESCRIPTOR)), + new SystemIndices.Feature( + "sds", + "system data stream feature", + Collections.emptyList(), + Collections.singletonList(SYSTEM_DATA_STREAM_DESCRIPTOR) + ) + ) + ), + clusterService ); } + private ClusterState executeTask(ClusterState clusterState) { + try { + return ClusterStateTaskExecutorUtils.executeAndAssertSuccessful(clusterState, executor, Collections.singletonList(task)); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + /** * When we upgrade Elasticsearch versions, existing indices may be newly * defined as system indices. If such indices are set without "hidden," we need @@ -75,6 +132,54 @@ public class SystemIndexMetadataUpgradeServiceTests extends ESTestCase { assertSystemUpgradeAppliesHiddenSetting(hiddenIndexMetadata); } + public void testUpgradeDataStreamToSystemDataStream() { + IndexMetadata dsIndexMetadata = IndexMetadata.builder(SYSTEM_DATA_STREAM_INDEX_NAME) + .system(false) + .settings(getSettingsBuilder().put(IndexMetadata.SETTING_INDEX_HIDDEN, true)) + .build(); + IndexMetadata fsIndexMetadata = IndexMetadata.builder(SYSTEM_DATA_STREAM_FAILSTORE_NAME) + .system(false) + .settings(getSettingsBuilder().put(IndexMetadata.SETTING_INDEX_HIDDEN, true)) + .build(); + DataStream.DataStreamIndices failureIndices = DataStream.DataStreamIndices.failureIndicesBuilder( + Collections.singletonList(fsIndexMetadata.getIndex()) + ).build(); + DataStream dataStream = DataStream.builder(SYSTEM_DATA_STREAM_NAME, Collections.singletonList(dsIndexMetadata.getIndex())) + .setFailureIndices(failureIndices) + .setHidden(false) + .setSystem(false) + .build(); + + assertTrue(dataStream.containsIndex(dsIndexMetadata.getIndex().getName())); + assertTrue(dataStream.containsIndex(fsIndexMetadata.getIndex().getName())); + + Metadata.Builder clusterMetadata = new Metadata.Builder(); + clusterMetadata.put(dataStream); + clusterMetadata.put(dsIndexMetadata, true); + clusterMetadata.put(fsIndexMetadata, true); + + ClusterState clusterState = ClusterState.builder(new ClusterName("system-index-metadata-upgrade-service-tests")) + .metadata(clusterMetadata.build()) + .customs(Map.of()) + .build(); + + service.submitUpdateTask(Collections.emptyList(), Collections.singletonList(dataStream)); + // Execute a metadata upgrade task on the initial cluster state + ClusterState newState = executeTask(clusterState); + + DataStream updatedDataStream = newState.metadata().dataStreams().get(dataStream.getName()); + assertThat(updatedDataStream.isSystem(), equalTo(true)); + assertThat(updatedDataStream.isHidden(), equalTo(true)); + + IndexMetadata updatedIndexMetadata = newState.metadata().index(dsIndexMetadata.getIndex().getName()); + assertThat(updatedIndexMetadata.isSystem(), equalTo(true)); + assertThat(updatedIndexMetadata.isHidden(), equalTo(true)); + + IndexMetadata updatedFailstoreMetadata = newState.metadata().index(fsIndexMetadata.getIndex().getName()); + assertThat(updatedFailstoreMetadata.isSystem(), equalTo(true)); + assertThat(updatedFailstoreMetadata.isHidden(), equalTo(true)); + } + /** * If a system index erroneously is set to visible, we should remedy that situation. */ @@ -209,7 +314,7 @@ public class SystemIndexMetadataUpgradeServiceTests extends ESTestCase { assertThat(service.requiresUpdate(systemVisibleIndex), equalTo(true)); } - private void assertSystemUpgradeAppliesHiddenSetting(IndexMetadata hiddenIndexMetadata) throws Exception { + private void assertSystemUpgradeAppliesHiddenSetting(IndexMetadata hiddenIndexMetadata) { assertTrue("Metadata should require update but does not", service.requiresUpdate(hiddenIndexMetadata)); Metadata.Builder clusterMetadata = new Metadata.Builder(); clusterMetadata.put(IndexMetadata.builder(hiddenIndexMetadata)); @@ -219,8 +324,9 @@ public class SystemIndexMetadataUpgradeServiceTests extends ESTestCase { .customs(Map.of()) .build(); + service.submitUpdateTask(Collections.singletonList(hiddenIndexMetadata.getIndex()), Collections.emptyList()); // Get a metadata upgrade task and execute it on the initial cluster state - ClusterState newState = service.getTask().execute(clusterState); + ClusterState newState = executeTask(clusterState); IndexMetadata result = newState.metadata().index(SYSTEM_INDEX_NAME); assertThat(result.isSystem(), equalTo(true)); @@ -237,8 +343,9 @@ public class SystemIndexMetadataUpgradeServiceTests extends ESTestCase { .customs(Map.of()) .build(); + service.submitUpdateTask(Collections.singletonList(visibleAliasMetadata.getIndex()), Collections.emptyList()); // Get a metadata upgrade task and execute it on the initial cluster state - ClusterState newState = service.getTask().execute(clusterState); + ClusterState newState = executeTask(clusterState); IndexMetadata result = newState.metadata().index(SYSTEM_INDEX_NAME); assertThat(result.isSystem(), equalTo(true)); From fd626a288bb13aac6fd883f30d1b2fc39f3f1f90 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 22 Feb 2025 07:51:35 +1100 Subject: [PATCH 19/27] Mute org.elasticsearch.upgrades.DataStreamsUpgradeIT testUpgradeDataStream #123189 --- muted-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index 9cb8eab0dd5d..0c464c3ae47b 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -335,6 +335,9 @@ tests: - class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT method: testStopQueryLocal issue: https://github.com/elastic/elasticsearch/issues/121672 +- class: org.elasticsearch.upgrades.DataStreamsUpgradeIT + method: testUpgradeDataStream + issue: https://github.com/elastic/elasticsearch/issues/123189 # Examples: # From f7e4d7cf8ad59817a70a99fdeec5a6f852ba80ed Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 22 Feb 2025 08:37:24 +1100 Subject: [PATCH 20/27] Mute org.elasticsearch.smoketest.DocsClientYamlTestSuiteIT test {yaml=reference/snapshot-restore/restore-snapshot/line_408} #123192 --- muted-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index 0c464c3ae47b..b952965acfd8 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -338,6 +338,9 @@ tests: - class: org.elasticsearch.upgrades.DataStreamsUpgradeIT method: testUpgradeDataStream issue: https://github.com/elastic/elasticsearch/issues/123189 +- class: org.elasticsearch.smoketest.DocsClientYamlTestSuiteIT + method: test {yaml=reference/snapshot-restore/restore-snapshot/line_408} + issue: https://github.com/elastic/elasticsearch/issues/123192 # Examples: # From 1ca04b7baea10563631a12773f2f4342e9851b3c Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Fri, 21 Feb 2025 13:55:32 -0800 Subject: [PATCH 21/27] Capture core dump files from tests (#123169) When running Elasticsearch in tests we occassionally have JDK crashes. It's important to capture the state of the JVM at the time of the crash. We currently capture the hs_err_pid file for the crash, but the resulting core file exists in a directory that is no captured. This commit adjusts the capture patterns to also get core files. --- .../gradle/internal/ElasticsearchBuildCompletePlugin.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchBuildCompletePlugin.java b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchBuildCompletePlugin.java index b1207a2f5161..065a57f801c9 100644 --- a/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchBuildCompletePlugin.java +++ b/build-tools-internal/src/main/java/org/elasticsearch/gradle/internal/ElasticsearchBuildCompletePlugin.java @@ -110,6 +110,8 @@ public abstract class ElasticsearchBuildCompletePlugin implements Plugin Date: Fri, 21 Feb 2025 17:06:25 -0500 Subject: [PATCH 22/27] Add health indicator impact to HealthPeriodicLogger (#122390) --- docs/changelog/122390.yaml | 5 ++ .../health/HealthPeriodicLogger.java | 29 +++++++--- .../node/DiskHealthIndicatorService.java | 3 +- .../health/HealthPeriodicLoggerTests.java | 53 +++++++++++++++++-- 4 files changed, 76 insertions(+), 14 deletions(-) create mode 100644 docs/changelog/122390.yaml diff --git a/docs/changelog/122390.yaml b/docs/changelog/122390.yaml new file mode 100644 index 000000000000..4338519ad60b --- /dev/null +++ b/docs/changelog/122390.yaml @@ -0,0 +1,5 @@ +pr: 122390 +summary: Add health indicator impact to `HealthPeriodicLogger` +area: Health +type: enhancement +issues: [] diff --git a/server/src/main/java/org/elasticsearch/health/HealthPeriodicLogger.java b/server/src/main/java/org/elasticsearch/health/HealthPeriodicLogger.java index cd6b7c7c7cd8..d7a2762556f1 100644 --- a/server/src/main/java/org/elasticsearch/health/HealthPeriodicLogger.java +++ b/server/src/main/java/org/elasticsearch/health/HealthPeriodicLogger.java @@ -52,10 +52,10 @@ import static org.elasticsearch.health.HealthStatus.GREEN; import static org.elasticsearch.health.HealthStatus.RED; /** - * This class periodically logs the results of the Health API to the standard Elasticsearch server log file. It a lifecycle - * aware component because it health depends on other lifecycle aware components. This means: + * This class periodically logs the results of the Health API to the standard Elasticsearch server log file. It is a lifecycle + * aware component because it depends on other lifecycle aware components. This means: * - We do not schedule any jobs until the lifecycle state is STARTED - * - When the lifecycle state becomes STOPPED, do not schedule any more runs, but we do let the current one finish + * - When the lifecycle state becomes STOPPED, we do not schedule any more runs, but we do let the current one finish * - When the lifecycle state becomes CLOSED, we will interrupt the current run as well. */ public class HealthPeriodicLogger extends AbstractLifecycleComponent implements ClusterStateListener, SchedulerEngine.Listener { @@ -361,11 +361,24 @@ public class HealthPeriodicLogger extends AbstractLifecycleComponent implements String.format(Locale.ROOT, "%s.%s.status", HEALTH_FIELD_PREFIX, indicatorResult.name()), indicatorResult.status().xContentValue() ); - if (GREEN.equals(indicatorResult.status()) == false && indicatorResult.details() != null) { - result.put( - String.format(Locale.ROOT, "%s.%s.details", HEALTH_FIELD_PREFIX, indicatorResult.name()), - Strings.toString(indicatorResult.details()) - ); + if (GREEN.equals(indicatorResult.status()) == false) { + // indicator details + if (indicatorResult.details() != null) { + result.put( + String.format(Locale.ROOT, "%s.%s.details", HEALTH_FIELD_PREFIX, indicatorResult.name()), + Strings.toString(indicatorResult.details()) + ); + } + // indicator impact + if (indicatorResult.impacts() != null) { + indicatorResult.impacts() + .forEach( + impact -> result.put( + String.format(Locale.ROOT, "%s.%s.%s.impacted", HEALTH_FIELD_PREFIX, indicatorResult.name(), impact.id()), + true + ) + ); + } } }); diff --git a/server/src/main/java/org/elasticsearch/health/node/DiskHealthIndicatorService.java b/server/src/main/java/org/elasticsearch/health/node/DiskHealthIndicatorService.java index 841973911d15..db5500585979 100644 --- a/server/src/main/java/org/elasticsearch/health/node/DiskHealthIndicatorService.java +++ b/server/src/main/java/org/elasticsearch/health/node/DiskHealthIndicatorService.java @@ -66,7 +66,8 @@ public class DiskHealthIndicatorService implements HealthIndicatorService { private static final Logger logger = LogManager.getLogger(DiskHealthIndicatorService.class); - private static final String IMPACT_INGEST_UNAVAILABLE_ID = "ingest_capability_unavailable"; + // VisibleForTesting + public static final String IMPACT_INGEST_UNAVAILABLE_ID = "ingest_capability_unavailable"; private static final String IMPACT_INGEST_AT_RISK_ID = "ingest_capability_at_risk"; private static final String IMPACT_CLUSTER_STABILITY_AT_RISK_ID = "cluster_stability_at_risk"; private static final String IMPACT_CLUSTER_FUNCTIONALITY_UNAVAILABLE_ID = "cluster_functionality_unavailable"; diff --git a/server/src/test/java/org/elasticsearch/health/HealthPeriodicLoggerTests.java b/server/src/test/java/org/elasticsearch/health/HealthPeriodicLoggerTests.java index e4bb23b09286..43d8a74395f1 100644 --- a/server/src/test/java/org/elasticsearch/health/HealthPeriodicLoggerTests.java +++ b/server/src/test/java/org/elasticsearch/health/HealthPeriodicLoggerTests.java @@ -19,6 +19,7 @@ import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.node.DiscoveryNode; import org.elasticsearch.cluster.node.DiscoveryNodeRole; import org.elasticsearch.cluster.node.DiscoveryNodeUtils; +import org.elasticsearch.cluster.routing.allocation.shards.ShardsAvailabilityHealthIndicatorService; import org.elasticsearch.cluster.routing.allocation.shards.ShardsAvailabilityHealthIndicatorServiceTests; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Strings; @@ -28,6 +29,7 @@ import org.elasticsearch.common.scheduler.SchedulerEngine; import org.elasticsearch.common.settings.ClusterSettings; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.core.TimeValue; +import org.elasticsearch.health.node.DiskHealthIndicatorService; import org.elasticsearch.telemetry.TelemetryProvider; import org.elasticsearch.telemetry.metric.LongGaugeMetric; import org.elasticsearch.telemetry.metric.MeterRegistry; @@ -51,9 +53,12 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.BiConsumer; import java.util.function.Consumer; +import static org.elasticsearch.cluster.routing.allocation.shards.ShardsAvailabilityHealthIndicatorService.PRIMARY_UNASSIGNED_IMPACT_ID; +import static org.elasticsearch.cluster.routing.allocation.shards.ShardsAvailabilityHealthIndicatorService.REPLICA_UNASSIGNED_IMPACT_ID; import static org.elasticsearch.health.HealthStatus.GREEN; import static org.elasticsearch.health.HealthStatus.RED; import static org.elasticsearch.health.HealthStatus.YELLOW; +import static org.elasticsearch.health.node.DiskHealthIndicatorService.IMPACT_INGEST_UNAVAILABLE_ID; import static org.elasticsearch.test.ClusterServiceUtils.createClusterService; import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; @@ -125,9 +130,9 @@ public class HealthPeriodicLoggerTests extends ESTestCase { Map loggerResults = HealthPeriodicLogger.convertToLoggedFields(results); - // verify that the number of fields is the number of indicators + 4 - // (for overall and for message, plus details for the two yellow indicators) - assertThat(loggerResults.size(), equalTo(results.size() + 4)); + // verify that the number of fields is the number of indicators + 7 + // (for overall and for message, plus details for the two yellow indicators, plus three impact) + assertThat(loggerResults.size(), equalTo(results.size() + 7)); // test indicator status assertThat(loggerResults.get(makeHealthStatusString("master_is_stable")), equalTo("green")); @@ -165,6 +170,17 @@ public class HealthPeriodicLoggerTests extends ESTestCase { equalTo(String.format(Locale.ROOT, "health=%s [disk,shards_availability]", overallStatus.xContentValue())) ); + // test impact + assertThat(loggerResults.get(makeHealthImpactString(DiskHealthIndicatorService.NAME, IMPACT_INGEST_UNAVAILABLE_ID)), equalTo(true)); + assertThat( + loggerResults.get(makeHealthImpactString(ShardsAvailabilityHealthIndicatorService.NAME, PRIMARY_UNASSIGNED_IMPACT_ID)), + equalTo(true) + ); + assertThat( + loggerResults.get(makeHealthImpactString(ShardsAvailabilityHealthIndicatorService.NAME, REPLICA_UNASSIGNED_IMPACT_ID)), + equalTo(true) + ); + // test empty results { List empty = new ArrayList<>(); @@ -793,7 +809,15 @@ public class HealthPeriodicLoggerTests extends ESTestCase { 1 ) ), - null, + List.of( + new HealthIndicatorImpact( + DiskHealthIndicatorService.NAME, + IMPACT_INGEST_UNAVAILABLE_ID, + 2, + "description", + List.of(ImpactArea.INGEST) + ) + ), null ); var shardsAvailable = new HealthIndicatorResult( @@ -801,7 +825,22 @@ public class HealthPeriodicLoggerTests extends ESTestCase { YELLOW, null, new SimpleHealthIndicatorDetails(ShardsAvailabilityHealthIndicatorServiceTests.addDefaults(Map.of())), - null, + List.of( + new HealthIndicatorImpact( + ShardsAvailabilityHealthIndicatorService.NAME, + PRIMARY_UNASSIGNED_IMPACT_ID, + 2, + "description", + List.of(ImpactArea.SEARCH) + ), + new HealthIndicatorImpact( + ShardsAvailabilityHealthIndicatorService.NAME, + REPLICA_UNASSIGNED_IMPACT_ID, + 2, + "description", + List.of(ImpactArea.SEARCH) + ) + ), null ); @@ -846,6 +885,10 @@ public class HealthPeriodicLoggerTests extends ESTestCase { return String.format(Locale.ROOT, "%s.%s.details", HealthPeriodicLogger.HEALTH_FIELD_PREFIX, key); } + private String makeHealthImpactString(String indicatorName, String impact) { + return String.format(Locale.ROOT, "%s.%s.%s.impacted", HealthPeriodicLogger.HEALTH_FIELD_PREFIX, indicatorName, impact); + } + private HealthPeriodicLogger createAndInitHealthPeriodicLogger( ClusterService clusterService, HealthService testHealthService, From 2c34d95977fd18675ff545ef2ed94e72fc2cdbda Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 22 Feb 2025 11:10:37 +1100 Subject: [PATCH 23/27] Mute org.elasticsearch.xpack.ilm.actions.SearchableSnapshotActionIT testRestoredIndexManagedByLocalPolicySkipsIllegalActions #123202 --- muted-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index b952965acfd8..e097cff89737 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -341,6 +341,9 @@ tests: - class: org.elasticsearch.smoketest.DocsClientYamlTestSuiteIT method: test {yaml=reference/snapshot-restore/restore-snapshot/line_408} issue: https://github.com/elastic/elasticsearch/issues/123192 +- class: org.elasticsearch.xpack.ilm.actions.SearchableSnapshotActionIT + method: testRestoredIndexManagedByLocalPolicySkipsIllegalActions + issue: https://github.com/elastic/elasticsearch/issues/123202 # Examples: # From 0fee331c28d15afa8c1d3c17d11ab6a587d589c8 Mon Sep 17 00:00:00 2001 From: elasticsearchmachine <58790826+elasticsearchmachine@users.noreply.github.com> Date: Sat, 22 Feb 2025 11:14:25 +1100 Subject: [PATCH 24/27] Mute org.elasticsearch.xpack.ilm.TimeSeriesLifecycleActionsIT testHistoryIsWrittenWithFailure #123203 --- muted-tests.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/muted-tests.yml b/muted-tests.yml index e097cff89737..44850050c63a 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -344,6 +344,9 @@ tests: - class: org.elasticsearch.xpack.ilm.actions.SearchableSnapshotActionIT method: testRestoredIndexManagedByLocalPolicySkipsIllegalActions issue: https://github.com/elastic/elasticsearch/issues/123202 +- class: org.elasticsearch.xpack.ilm.TimeSeriesLifecycleActionsIT + method: testHistoryIsWrittenWithFailure + issue: https://github.com/elastic/elasticsearch/issues/123203 # Examples: # From df71ccf4410a9eb785a2631b77e092856342f124 Mon Sep 17 00:00:00 2001 From: Oleksandr Kolomiiets Date: Fri, 21 Feb 2025 16:28:13 -0800 Subject: [PATCH 25/27] Don't run FieldExtractorIT#testScaledFloat using JDK17 (#123199) --- .../xpack/esql/qa/rest/FieldExtractorTestCase.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/FieldExtractorTestCase.java b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/FieldExtractorTestCase.java index 5e1755adbe63..11aa9a43fa5a 100644 --- a/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/FieldExtractorTestCase.java +++ b/x-pack/plugin/esql/qa/server/src/main/java/org/elasticsearch/xpack/esql/qa/rest/FieldExtractorTestCase.java @@ -221,6 +221,11 @@ public abstract class FieldExtractorTestCase extends ESRestTestCase { } public void testScaledFloat() throws IOException { + // Running this on 17 when nodes in cluster run JDK >17 triggers an assert due to a mismatch + // of results produced by Double#toString for some specific numbers. + // See https://github.com/elastic/elasticsearch/issues/122984. + assumeTrue("JDK version greater than 17", Runtime.version().feature() > 17); + double value = randomBoolean() ? randomDoubleBetween(-Double.MAX_VALUE, Double.MAX_VALUE, true) : randomFloat(); // Scale factors less than about 5.6e-309 will result in NaN (due to 1/scaleFactor being infinity) double scalingFactor = randomDoubleBetween(1e-308, Double.MAX_VALUE, false); From 7cbd305a1605bd0fc3c181fb1790952f23fceaef Mon Sep 17 00:00:00 2001 From: Jack Conradson Date: Fri, 21 Feb 2025 17:45:39 -0800 Subject: [PATCH 26/27] Prune extraneous files entitlements paths to prevent incorrect binary search (#123177) --- .../runtime/policy/FileAccessTree.java | 20 ++++++++++++++++-- .../runtime/policy/FileAccessTreeTests.java | 21 +++++++++++++++++++ 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTree.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTree.java index 98076af51ae6..660459f06d58 100644 --- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTree.java +++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTree.java @@ -49,8 +49,24 @@ public final class FileAccessTree { readPaths.sort(String::compareTo); writePaths.sort(String::compareTo); - this.readPaths = readPaths.toArray(new String[0]); - this.writePaths = writePaths.toArray(new String[0]); + this.readPaths = pruneSortedPaths(readPaths).toArray(new String[0]); + this.writePaths = pruneSortedPaths(writePaths).toArray(new String[0]); + } + + private static List pruneSortedPaths(List paths) { + List prunedReadPaths = new ArrayList<>(); + if (paths.isEmpty() == false) { + String currentPath = paths.get(0); + prunedReadPaths.add(currentPath); + for (int i = 1; i < paths.size(); ++i) { + String nextPath = paths.get(i); + if (nextPath.startsWith(currentPath) == false) { + prunedReadPaths.add(nextPath); + currentPath = nextPath; + } + } + } + return prunedReadPaths; } public static FileAccessTree of(FilesEntitlement filesEntitlement, PathLookup pathLookup) { diff --git a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java index 218fc0c95672..4eb3620c276f 100644 --- a/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java +++ b/libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/FileAccessTreeTests.java @@ -96,6 +96,27 @@ public class FileAccessTreeTests extends ESTestCase { assertThat(tree.canWrite(path("foo/bar")), is(true)); } + public void testPrunedPaths() { + var tree = accessTree(entitlement("foo", "read", "foo/baz", "read", "foo/bar", "read")); + assertThat(tree.canRead(path("foo")), is(true)); + assertThat(tree.canWrite(path("foo")), is(false)); + assertThat(tree.canRead(path("foo/bar")), is(true)); + assertThat(tree.canWrite(path("foo/bar")), is(false)); + assertThat(tree.canRead(path("foo/baz")), is(true)); + assertThat(tree.canWrite(path("foo/baz")), is(false)); + // also test a non-existent subpath + assertThat(tree.canRead(path("foo/barf")), is(true)); + assertThat(tree.canWrite(path("foo/barf")), is(false)); + + tree = accessTree(entitlement("foo", "read", "foo/bar", "read_write")); + assertThat(tree.canRead(path("foo")), is(true)); + assertThat(tree.canWrite(path("foo")), is(false)); + assertThat(tree.canRead(path("foo/bar")), is(true)); + assertThat(tree.canWrite(path("foo/bar")), is(true)); + assertThat(tree.canRead(path("foo/baz")), is(true)); + assertThat(tree.canWrite(path("foo/baz")), is(false)); + } + public void testReadWithRelativePath() { for (var dir : List.of("config", "home")) { var tree = accessTree(entitlement(Map.of("relative_path", "foo", "mode", "read", "relative_to", dir))); From 8b25a7281d395176102b379b03a4a67d802ae5d4 Mon Sep 17 00:00:00 2001 From: Parker Timmins Date: Fri, 21 Feb 2025 20:20:17 -0600 Subject: [PATCH 27/27] Fix broken test caused by setting old write index to read-only verified (#123190) #122887 set read-only on the source indices of a data stream reindex. To test behavior when the source index was already read-only, testDataStreamUpgrade sometimes set the old write index to read-only. But the rest end point for adding a read-only block always sets verifed-read-only. This caused the old write index to not need to be upgraded, resulting in an incorrect value for total_indices_requiring_upgrade --- muted-tests.yml | 4 +--- .../java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/muted-tests.yml b/muted-tests.yml index 44850050c63a..3401798707ed 100644 --- a/muted-tests.yml +++ b/muted-tests.yml @@ -335,9 +335,6 @@ tests: - class: org.elasticsearch.xpack.esql.action.CrossClusterAsyncQueryStopIT method: testStopQueryLocal issue: https://github.com/elastic/elasticsearch/issues/121672 -- class: org.elasticsearch.upgrades.DataStreamsUpgradeIT - method: testUpgradeDataStream - issue: https://github.com/elastic/elasticsearch/issues/123189 - class: org.elasticsearch.smoketest.DocsClientYamlTestSuiteIT method: test {yaml=reference/snapshot-restore/restore-snapshot/line_408} issue: https://github.com/elastic/elasticsearch/issues/123192 @@ -348,6 +345,7 @@ tests: method: testHistoryIsWrittenWithFailure issue: https://github.com/elastic/elasticsearch/issues/123203 + # Examples: # # Mute a single test case in a YAML test suite: diff --git a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java index 77ab71b5db6e..1d320f97a41a 100644 --- a/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java +++ b/x-pack/qa/rolling-upgrade/src/test/java/org/elasticsearch/upgrades/DataStreamsUpgradeIT.java @@ -548,9 +548,6 @@ public class DataStreamsUpgradeIT extends AbstractUpgradeTestCase { if (randomBoolean()) { closeIndex(oldIndexName); } - if (randomBoolean()) { - assertOK(client().performRequest(new Request("PUT", oldIndexName + "/_block/read_only"))); - } } Request reindexRequest = new Request("POST", "/_migration/reindex"); reindexRequest.setJsonEntity(Strings.format("""