Skip to content

Commit 527b3c4

Browse files
authored
Merge branch 'main' into entitlements/logs-dir-bootstrap
2 parents fefc68c + 8b4f159 commit 527b3c4

File tree

51 files changed

+651
-317
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+651
-317
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ distribution/docker/src @elastic/es-delivery
4949
# Core/Infra
5050
distribution/tools @elastic/es-core-infra
5151
libs/core @elastic/es-core-infra
52+
libs/entitlement @elastic/es-core-infra
5253
libs/logging @elastic/es-core-infra
5354
libs/native @elastic/es-core-infra
5455
libs/plugin-analysis-api @elastic/es-core-infra

docs/changelog/121942.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 121942
2+
summary: Allow partial results in ES|QL
3+
area: ES|QL
4+
type: enhancement
5+
issues: []

docs/changelog/122610.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 122610
2+
summary: Canonicalize processor names and types in `IngestStats`
3+
area: Ingest Node
4+
type: bug
5+
issues: []

docs/changelog/122653.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 122653
2+
summary: Knn vector rescoring to sort score docs
3+
area: Vector Search
4+
type: bug
5+
issues:
6+
- 119711

modules/transport-netty4/src/test/java/org/elasticsearch/transport/netty4/Netty4WriteThrottlingHandlerTests.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ public void testThrottleLargeCompositeMessage() {
109109
Netty4WriteThrottlingHandler.MAX_BYTES_PER_WRITE * fullSizeChunks + extraChunkSize
110110
);
111111
int splitOffset = randomIntBetween(0, messageBytes.length);
112+
int lastChunkSizeOfTheFirstSplit = splitOffset % Netty4WriteThrottlingHandler.MAX_BYTES_PER_WRITE;
112113
final BytesReference message = CompositeBytesReference.of(
113114
new BytesArray(messageBytes, 0, splitOffset),
114115
new BytesArray(messageBytes, splitOffset, messageBytes.length - splitOffset)
@@ -120,7 +121,9 @@ public void testThrottleLargeCompositeMessage() {
120121
assertFalse(promise.isDone());
121122
embeddedChannel.flush();
122123
assertTrue(promise.isDone());
123-
assertThat(seen, hasSize(oneOf(fullSizeChunks, fullSizeChunks + 1)));
124+
// If the extra chunk size is greater than the last chunk size for the first half of the split, it means we will need to send
125+
// (extraChunkSize - lastChunkSizeOfTheFirstSplit) bytes as the very last chunk of the entire message.
126+
assertThat(seen, hasSize(oneOf(fullSizeChunks, fullSizeChunks + 1 + (extraChunkSize > lastChunkSizeOfTheFirstSplit ? 1 : 0))));
124127
assertTrue(capturingHandler.didWriteAfterThrottled);
125128
assertBufferEquals(Unpooled.compositeBuffer().addComponents(true, seen), message);
126129
}

muted-tests.yml

Lines changed: 83 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,6 @@ tests:
6969
- class: org.elasticsearch.xpack.test.rest.XPackRestIT
7070
method: test {p0=transform/transforms_start_stop/Test start already started transform}
7171
issue: https://github.com/elastic/elasticsearch/issues/98802
72-
- class: org.elasticsearch.action.search.SearchPhaseControllerTests
73-
method: testProgressListener
74-
issue: https://github.com/elastic/elasticsearch/issues/116149
7572
- class: org.elasticsearch.xpack.deprecation.DeprecationHttpIT
7673
method: testDeprecatedSettingsReturnWarnings
7774
issue: https://github.com/elastic/elasticsearch/issues/108628
@@ -153,9 +150,6 @@ tests:
153150
issue: https://github.com/elastic/elasticsearch/issues/117740
154151
- class: org.elasticsearch.xpack.security.authc.ldap.MultiGroupMappingIT
155152
issue: https://github.com/elastic/elasticsearch/issues/119599
156-
- class: org.elasticsearch.search.profile.dfs.DfsProfilerIT
157-
method: testProfileDfs
158-
issue: https://github.com/elastic/elasticsearch/issues/119711
159153
- class: org.elasticsearch.multi_cluster.MultiClusterYamlTestSuiteIT
160154
issue: https://github.com/elastic/elasticsearch/issues/119983
161155
- class: org.elasticsearch.xpack.test.rest.XPackRestIT
@@ -219,41 +213,14 @@ tests:
219213
- class: org.elasticsearch.action.search.SearchProgressActionListenerIT
220214
method: testSearchProgressWithQuery
221215
issue: https://github.com/elastic/elasticsearch/issues/120994
222-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
223-
method: testSuggestProfilesWithName
224-
issue: https://github.com/elastic/elasticsearch/issues/121022
225-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
226-
method: testProfileAPIsWhenIndexNotCreated
227-
issue: https://github.com/elastic/elasticsearch/issues/121096
228-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
229-
method: testGetProfiles
230-
issue: https://github.com/elastic/elasticsearch/issues/121101
231-
- class: org.elasticsearch.xpack.security.authc.service.ServiceAccountSingleNodeTests
232-
method: testAuthenticateWithServiceFileToken
233-
issue: https://github.com/elastic/elasticsearch/issues/120988
234-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
235-
method: testUpdateProfileData
236-
issue: https://github.com/elastic/elasticsearch/issues/121108
237216
- class: org.elasticsearch.backwards.MixedClusterClientYamlTestSuiteIT
238217
method: test {p0=nodes.stats/11_indices_metrics/indices mappings exact count test for indices level}
239218
issue: https://github.com/elastic/elasticsearch/issues/120950
240-
- class: org.elasticsearch.xpack.security.authc.jwt.JwtRealmSingleNodeTests
241-
method: testActivateProfileForJWT
242-
issue: https://github.com/elastic/elasticsearch/issues/120983
243-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
244-
method: testProfileIndexAutoCreation
245-
issue: https://github.com/elastic/elasticsearch/issues/120987
246219
- class: org.elasticsearch.xpack.security.FileSettingsRoleMappingsRestartIT
247220
method: testFileSettingsReprocessedOnRestartWithoutVersionChange
248221
issue: https://github.com/elastic/elasticsearch/issues/120964
249-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
250-
method: testGetUsersWithProfileUidWhenProfileIndexDoesNotExists
251-
issue: https://github.com/elastic/elasticsearch/issues/121179
252222
- class: org.elasticsearch.xpack.ml.integration.PyTorchModelIT
253223
issue: https://github.com/elastic/elasticsearch/issues/121165
254-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
255-
method: testSetEnabled
256-
issue: https://github.com/elastic/elasticsearch/issues/121183
257224
- class: org.elasticsearch.xpack.test.rest.XPackRestIT
258225
method: test {p0=transform/*}
259226
issue: https://github.com/elastic/elasticsearch/issues/120816
@@ -292,29 +259,8 @@ tests:
292259
- class: org.elasticsearch.smoketest.DocsClientYamlTestSuiteIT
293260
method: test {yaml=reference/snapshot-restore/apis/get-snapshot-api/line_751}
294261
issue: https://github.com/elastic/elasticsearch/issues/121345
295-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
296-
method: testHasPrivileges
297-
issue: https://github.com/elastic/elasticsearch/issues/121346
298-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
299-
method: testActivateProfile
300-
issue: https://github.com/elastic/elasticsearch/issues/121151
301262
- class: org.elasticsearch.test.rest.yaml.CcsCommonYamlTestSuiteIT
302263
issue: https://github.com/elastic/elasticsearch/issues/121407
303-
- class: org.elasticsearch.xpack.security.authc.jwt.JwtRealmSingleNodeTests
304-
method: testClientSecretRotation
305-
issue: https://github.com/elastic/elasticsearch/issues/120985
306-
- class: org.elasticsearch.xpack.security.authc.jwt.JwtRealmSingleNodeTests
307-
method: testGrantApiKeyForJWT
308-
issue: https://github.com/elastic/elasticsearch/issues/121039
309-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
310-
method: testGetUsersWithProfileUid
311-
issue: https://github.com/elastic/elasticsearch/issues/121483
312-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
313-
method: testSuggestProfilesWithHint
314-
issue: https://github.com/elastic/elasticsearch/issues/121116
315-
- class: org.elasticsearch.xpack.security.profile.ProfileIntegTests
316-
method: testSuggestProfileWithData
317-
issue: https://github.com/elastic/elasticsearch/issues/121258
318264
- class: org.elasticsearch.smoketest.DocsClientYamlTestSuiteIT
319265
method: test {yaml=reference/cat/health/cat-health-no-timestamp-example}
320266
issue: https://github.com/elastic/elasticsearch/issues/121867
@@ -377,6 +323,89 @@ tests:
377323
- class: org.elasticsearch.xpack.inference.mapper.SemanticInferenceMetadataFieldsRecoveryTests
378324
method: testSnapshotRecovery {p0=false p1=true}
379325
issue: https://github.com/elastic/elasticsearch/issues/122551
326+
- class: org.elasticsearch.index.mapper.ShapeGeometryFieldMapperTests
327+
method: testCartesianBoundsBlockLoader
328+
issue: https://github.com/elastic/elasticsearch/issues/122661
329+
- class: org.elasticsearch.entitlement.runtime.policy.PolicyParserTests
330+
method: testPolicyBuilderOnExternalPlugin
331+
issue: https://github.com/elastic/elasticsearch/issues/122663
332+
- class: org.elasticsearch.entitlement.runtime.policy.PolicyParserTests
333+
method: testParseFiles
334+
issue: https://github.com/elastic/elasticsearch/issues/122664
335+
- class: org.elasticsearch.entitlement.runtime.policy.PolicyParserTests
336+
method: testPolicyBuilder
337+
issue: https://github.com/elastic/elasticsearch/issues/122665
338+
- class: org.elasticsearch.entitlement.runtime.policy.PolicyParserFailureTests
339+
method: testEntitlementAbsolutePathWhenRelative
340+
issue: https://github.com/elastic/elasticsearch/issues/122666
341+
- class: org.elasticsearch.entitlement.qa.EntitlementsAllowedNonModularIT
342+
issue: https://github.com/elastic/elasticsearch/issues/122568
343+
- class: org.elasticsearch.entitlement.qa.EntitlementsDeniedIT
344+
issue: https://github.com/elastic/elasticsearch/issues/122566
345+
- class: org.elasticsearch.entitlement.qa.EntitlementsDeniedNonModularIT
346+
issue: https://github.com/elastic/elasticsearch/issues/122569
347+
- class: org.elasticsearch.entitlement.qa.EntitlementsAllowedIT
348+
issue: https://github.com/elastic/elasticsearch/issues/122680
349+
- class: org.elasticsearch.smoketest.DocsClientYamlTestSuiteIT
350+
method: test {yaml=reference/snapshot-restore/apis/get-snapshot-api/line_408}
351+
issue: https://github.com/elastic/elasticsearch/issues/122681
352+
- class: org.elasticsearch.xpack.autoscaling.storage.ReactiveStorageIT
353+
method: testScaleWhileShrinking
354+
issue: https://github.com/elastic/elasticsearch/issues/122119
355+
- class: org.elasticsearch.lucene.RollingUpgradeLuceneIndexCompatibilityTestCase
356+
method: testIndexUpgrade {p0=[9.1.0, 8.19.0, 8.19.0]}
357+
issue: https://github.com/elastic/elasticsearch/issues/122688
358+
- class: org.elasticsearch.lucene.RollingUpgradeLuceneIndexCompatibilityTestCase
359+
method: testRestoreIndex {p0=[9.1.0, 9.1.0, 8.19.0]}
360+
issue: https://github.com/elastic/elasticsearch/issues/122689
361+
- class: org.elasticsearch.lucene.RollingUpgradeLuceneIndexCompatibilityTestCase
362+
method: testClosedIndexUpgrade {p0=[9.1.0, 8.19.0, 8.19.0]}
363+
issue: https://github.com/elastic/elasticsearch/issues/122690
364+
- class: org.elasticsearch.lucene.RollingUpgradeLuceneIndexCompatibilityTestCase
365+
method: testRestoreIndex {p0=[9.1.0, 8.19.0, 8.19.0]}
366+
issue: https://github.com/elastic/elasticsearch/issues/122691
367+
- class: org.elasticsearch.xpack.searchablesnapshots.FrozenSearchableSnapshotsIntegTests
368+
method: testCreateAndRestorePartialSearchableSnapshot
369+
issue: https://github.com/elastic/elasticsearch/issues/122693
370+
- class: org.elasticsearch.lucene.RollingUpgradeLuceneIndexCompatibilityTestCase
371+
method: testClosedIndexUpgrade {p0=[9.1.0, 9.1.0, 8.19.0]}
372+
issue: https://github.com/elastic/elasticsearch/issues/122694
373+
- class: org.elasticsearch.lucene.RollingUpgradeLuceneIndexCompatibilityTestCase
374+
method: testClosedIndexUpgrade {p0=[9.1.0, 9.1.0, 9.1.0]}
375+
issue: https://github.com/elastic/elasticsearch/issues/122695
376+
- class: org.elasticsearch.lucene.RollingUpgradeLuceneIndexCompatibilityTestCase
377+
method: testIndexUpgrade {p0=[9.1.0, 9.1.0, 8.19.0]}
378+
issue: https://github.com/elastic/elasticsearch/issues/122696
379+
- class: org.elasticsearch.lucene.RollingUpgradeLuceneIndexCompatibilityTestCase
380+
method: testIndexUpgrade {p0=[9.1.0, 9.1.0, 9.1.0]}
381+
issue: https://github.com/elastic/elasticsearch/issues/122697
382+
- class: org.elasticsearch.lucene.RollingUpgradeLuceneIndexCompatibilityTestCase
383+
method: testRestoreIndex {p0=[9.1.0, 9.1.0, 9.1.0]}
384+
issue: https://github.com/elastic/elasticsearch/issues/122698
385+
- class: org.elasticsearch.lucene.RollingUpgradeSearchableSnapshotIndexCompatibilityIT
386+
method: testSearchableSnapshotUpgrade {p0=[9.1.0, 8.19.0, 8.19.0]}
387+
issue: https://github.com/elastic/elasticsearch/issues/122700
388+
- class: org.elasticsearch.lucene.RollingUpgradeSearchableSnapshotIndexCompatibilityIT
389+
method: testSearchableSnapshotUpgrade {p0=[9.1.0, 9.1.0, 8.19.0]}
390+
issue: https://github.com/elastic/elasticsearch/issues/122701
391+
- class: org.elasticsearch.lucene.RollingUpgradeSearchableSnapshotIndexCompatibilityIT
392+
method: testMountSearchableSnapshot {p0=[9.1.0, 8.19.0, 8.19.0]}
393+
issue: https://github.com/elastic/elasticsearch/issues/122702
394+
- class: org.elasticsearch.lucene.RollingUpgradeSearchableSnapshotIndexCompatibilityIT
395+
method: testMountSearchableSnapshot {p0=[9.1.0, 9.1.0, 8.19.0]}
396+
issue: https://github.com/elastic/elasticsearch/issues/122703
397+
- class: org.elasticsearch.lucene.RollingUpgradeSearchableSnapshotIndexCompatibilityIT
398+
method: testSearchableSnapshotUpgrade {p0=[9.1.0, 9.1.0, 9.1.0]}
399+
issue: https://github.com/elastic/elasticsearch/issues/122704
400+
- class: org.elasticsearch.lucene.RollingUpgradeSearchableSnapshotIndexCompatibilityIT
401+
method: testMountSearchableSnapshot {p0=[9.1.0, 9.1.0, 9.1.0]}
402+
issue: https://github.com/elastic/elasticsearch/issues/122705
403+
- class: org.elasticsearch.search.basic.SearchWithRandomDisconnectsIT
404+
method: testSearchWithRandomDisconnects
405+
issue: https://github.com/elastic/elasticsearch/issues/122707
406+
- class: org.elasticsearch.indices.recovery.IndexRecoveryIT
407+
method: testSourceThrottling
408+
issue: https://github.com/elastic/elasticsearch/issues/122712
380409

381410
# Examples:
382411
#

server/src/internalClusterTest/java/org/elasticsearch/cluster/PrevalidateNodeRemovalIT.java

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -179,28 +179,35 @@ public void testNodeRemovalFromRedClusterWithTimeout() throws Exception {
179179
// make it red!
180180
internalCluster().stopNode(node1);
181181
ensureRed(indexName);
182+
CountDownLatch stallPrevalidateShardPathActionLatch = new CountDownLatch(1);
182183
MockTransportService.getInstance(node2)
183184
.addRequestHandlingBehavior(TransportPrevalidateShardPathAction.ACTION_NAME + "[n]", (handler, request, channel, task) -> {
184185
logger.info("drop the check shards request");
186+
safeAwait(stallPrevalidateShardPathActionLatch);
187+
handler.messageReceived(request, channel, task);
185188
});
186-
PrevalidateNodeRemovalRequest req = PrevalidateNodeRemovalRequest.builder()
187-
.setNames(node2)
188-
.build(TEST_REQUEST_TIMEOUT)
189-
.masterNodeTimeout(TimeValue.timeValueSeconds(1))
190-
.timeout(TimeValue.timeValueSeconds(1));
191-
PrevalidateNodeRemovalResponse resp = client().execute(PrevalidateNodeRemovalAction.INSTANCE, req).get();
192-
assertFalse("prevalidation result should return false", resp.getPrevalidation().isSafe());
193-
String node2Id = getNodeId(node2);
194-
assertThat(
195-
resp.getPrevalidation().message(),
196-
equalTo("cannot prevalidate removal of nodes with the following IDs: [" + node2Id + "]")
197-
);
198-
assertThat(resp.getPrevalidation().nodes().size(), equalTo(1));
199-
NodesRemovalPrevalidation.NodeResult nodeResult = resp.getPrevalidation().nodes().get(0);
200-
assertThat(nodeResult.name(), equalTo(node2));
201-
assertFalse(nodeResult.result().isSafe());
202-
assertThat(nodeResult.result().message(), startsWith("failed contacting the node"));
203-
assertThat(nodeResult.result().reason(), equalTo(NodesRemovalPrevalidation.Reason.UNABLE_TO_VERIFY));
189+
try {
190+
PrevalidateNodeRemovalRequest req = PrevalidateNodeRemovalRequest.builder()
191+
.setNames(node2)
192+
.build(TEST_REQUEST_TIMEOUT)
193+
.masterNodeTimeout(TimeValue.timeValueSeconds(1))
194+
.timeout(TimeValue.timeValueSeconds(1));
195+
PrevalidateNodeRemovalResponse resp = client().execute(PrevalidateNodeRemovalAction.INSTANCE, req).get();
196+
assertFalse("prevalidation result should return false", resp.getPrevalidation().isSafe());
197+
String node2Id = getNodeId(node2);
198+
assertThat(
199+
resp.getPrevalidation().message(),
200+
equalTo("cannot prevalidate removal of nodes with the following IDs: [" + node2Id + "]")
201+
);
202+
assertThat(resp.getPrevalidation().nodes().size(), equalTo(1));
203+
NodesRemovalPrevalidation.NodeResult nodeResult = resp.getPrevalidation().nodes().get(0);
204+
assertThat(nodeResult.name(), equalTo(node2));
205+
assertFalse(nodeResult.result().isSafe());
206+
assertThat(nodeResult.result().message(), startsWith("failed contacting the node"));
207+
assertThat(nodeResult.result().reason(), equalTo(NodesRemovalPrevalidation.Reason.UNABLE_TO_VERIFY));
208+
} finally {
209+
stallPrevalidateShardPathActionLatch.countDown();
210+
}
204211
}
205212

206213
private void ensureRed(String indexName) throws Exception {

server/src/main/java/org/elasticsearch/TransportVersions.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ static TransportVersion def(int id) {
176176
public static final TransportVersion ML_INFERENCE_IBM_WATSONX_RERANK_ADDED = def(8_840_0_00);
177177
public static final TransportVersion COHERE_BIT_EMBEDDING_TYPE_SUPPORT_ADDED_BACKPORT_8_X = def(8_840_0_01);
178178
public static final TransportVersion REMOVE_ALL_APPLICABLE_SELECTOR_BACKPORT_8_X = def(8_840_0_02);
179+
public static final TransportVersion ESQL_RETRY_ON_SHARD_LEVEL_FAILURE_BACKPORT_8_19 = def(8_840_0_03);
180+
public static final TransportVersion ESQL_SUPPORT_PARTIAL_RESULTS_BACKPORT_8_19 = def(8_840_0_04);
179181
public static final TransportVersion ELASTICSEARCH_9_0 = def(9_000_0_00);
180182
public static final TransportVersion REMOVE_SNAPSHOT_FAILURES_90 = def(9_000_0_01);
181183
public static final TransportVersion TRANSPORT_STATS_HANDLING_TIME_REQUIRED_90 = def(9_000_0_02);
@@ -192,6 +194,7 @@ static TransportVersion def(int id) {
192194
public static final TransportVersion ESQL_LOOKUP_JOIN_SOURCE_TEXT = def(9_008_0_00);
193195
public static final TransportVersion REMOVE_ALL_APPLICABLE_SELECTOR = def(9_009_0_00);
194196
public static final TransportVersion SLM_UNHEALTHY_IF_NO_SNAPSHOT_WITHIN = def(9_010_0_00);
197+
public static final TransportVersion ESQL_SUPPORT_PARTIAL_RESULTS = def(9_011_0_00);
195198

196199
/*
197200
* STOP! READ THIS FIRST! No, really,

server/src/main/java/org/elasticsearch/action/search/CanMatchPreFilterSearchPhase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ public CanMatchNodeRequest.Shard buildShardLevelRequest(SearchShardIterator shar
387387
}
388388

389389
public void start() {
390-
if (shardsIts.size() == 0) {
390+
if (shardsIts.isEmpty()) {
391391
finishPhase();
392392
return;
393393
}

server/src/main/java/org/elasticsearch/action/search/SearchShardIterator.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
import org.elasticsearch.action.OriginalIndices;
1313
import org.elasticsearch.cluster.routing.ShardRouting;
14-
import org.elasticsearch.cluster.routing.ShardsIterator;
1514
import org.elasticsearch.common.util.PlainIterator;
1615
import org.elasticsearch.core.Nullable;
1716
import org.elasticsearch.core.TimeValue;
@@ -113,15 +112,6 @@ SearchShardTarget nextOrNull() {
113112
return null;
114113
}
115114

116-
/**
117-
* Return the number of shards remaining in this {@link ShardsIterator}
118-
*
119-
* @return number of shard remaining
120-
*/
121-
int remaining() {
122-
return targetNodesIterator.remaining();
123-
}
124-
125115
/**
126116
* Returns a non-null value if this request should use a specific search context instead of the latest one.
127117
*/

0 commit comments

Comments
 (0)