Skip to content

Commit ecf39ff

Browse files
committed
added changes for 1.24 release
Signed-off-by: Sarthak Jain <sarthak.jain@harness.io>
1 parent c537090 commit ecf39ff

File tree

3 files changed

+238
-14
lines changed

3 files changed

+238
-14
lines changed

README.md

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ To check compatibility of litmusctl with Chaos Center
2929
<th>litmusctl version</th>
3030
<th>Lowest Chaos Center supported version</th>
3131
<th>Highest Chaos Center supported version</th>
32+
<tr>
33+
<td>1.24.0</td>
34+
<td>3.0.0</td>
35+
<td>3.27.0</td>
36+
</tr>
3237
<tr>
3338
<td>1.23.0</td>
3439
<td>3.0.0</td>
@@ -64,11 +69,6 @@ To check compatibility of litmusctl with Chaos Center
6469
<td>3.0.0</td>
6570
<td>3.20.0</td>
6671
</tr>
67-
<tr>
68-
<td>1.16.0</td>
69-
<td>3.0.0</td>
70-
<td>3.19.0</td>
71-
</tr>
7272
</table>
7373

7474
## Installation
@@ -77,109 +77,109 @@ To install the latest version of litmusctl follow the below steps:
7777

7878
<table>
7979
<th>Platforms</th>
80+
<th>1.24.0</th>
8081
<th>1.23.0</th>
8182
<th>1.22.0</th>
8283
<th>1.21.0</th>
8384
<th>1.20.0</th>
8485
<th>1.19.0</th>
8586
<th>1.18.0</th>
8687
<th>1.17.0</th>
87-
<th>1.16.0</th>
8888
<th>master(Unreleased)</th>
8989
<tr>
9090
<td>litmusctl-darwin-amd64 (MacOS)</td>
91+
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-1.24.0.tar.gz">Click here</a></td>
9192
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-1.23.0.tar.gz">Click here</a></td>
9293
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-1.22.0.tar.gz">Click here</a></td>
9394
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-1.21.0.tar.gz">Click here</a></td>
9495
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-1.20.0.tar.gz">Click here</a></td>
9596
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-1.19.0.tar.gz">Click here</a></td>
9697
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-1.18.0.tar.gz">Click here</a></td>
9798
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-1.17.0.tar.gz">Click here</a></td>
98-
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-1.16.0.tar.gz">Click here</a></td>
9999
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-darwin-amd64-master.tar.gz">Click here</a></td>
100100
</tr>
101101
<tr>
102102
<td>litmusctl-linux-386</td>
103+
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-1.24.0.tar.gz">Click here</a></td>
103104
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-1.23.0.tar.gz">Click here</a></td>
104105
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-1.22.0.tar.gz">Click here</a></td>
105106
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-1.21.0.tar.gz">Click here</a></td>
106107
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-1.20.0.tar.gz">Click here</a></td>
107108
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-1.19.0.tar.gz">Click here</a></td>
108109
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-1.18.0.tar.gz">Click here</a></td>
109110
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-1.17.0.tar.gz">Click here</a></td>
110-
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-1.16.0.tar.gz">Click here</a></td>
111111
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-386-master.tar.gz">Click here</a></td>
112112
</tr>
113113
<tr>
114114
<td>litmusctl-linux-amd64</td>
115+
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-1.24.0.tar.gz">Click here</a></td>
115116
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-1.23.0.tar.gz">Click here</a></td>
116117
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-1.22.0.tar.gz">Click here</a></td>
117118
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-1.21.0.tar.gz">Click here</a></td>
118119
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-1.20.0.tar.gz">Click here</a></td>
119120
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-1.19.0.tar.gz">Click here</a></td>
120121
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-1.18.0.tar.gz">Click here</a></td>
121122
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-1.17.0.tar.gz">Click here</a></td>
122-
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-1.16.0.tar.gz">Click here</a></td>
123123
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-amd64-master.tar.gz">Click here</a></td>
124124
</tr>
125125
<tr>
126126
<td>litmusctl-linux-arm</td>
127+
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-1.24.0.tar.gz">Click here</a></td>
127128
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-1.23.0.tar.gz">Click here</a></td>
128129
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-1.22.0.tar.gz">Click here</a></td>
129130
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-1.21.0.tar.gz">Click here</a></td>
130131
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-1.20.0.tar.gz">Click here</a></td>
131132
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-1.19.0.tar.gz">Click here</a></td>
132133
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-1.18.0.tar.gz">Click here</a></td>
133134
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-1.17.0.tar.gz">Click here</a></td>
134-
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-1.16.0.tar.gz">Click here</a></td>
135135
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm-master.tar.gz">Click here</a></td>
136136
</tr>
137137
<tr>
138138
<td>litmusctl-linux-arm64</td>
139+
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-1.24.0.tar.gz">Click here</a></td>
139140
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-1.23.0.tar.gz">Click here</a></td>
140141
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-1.22.0.tar.gz">Click here</a></td>
141142
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-1.21.0.tar.gz">Click here</a></td>
142143
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-1.20.0.tar.gz">Click here</a></td>
143144
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-1.19.0.tar.gz">Click here</a></td>
144145
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-1.18.0.tar.gz">Click here</a></td>
145146
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-1.17.0.tar.gz">Click here</a></td>
146-
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-1.16.0.tar.gz">Click here</a></td>
147147
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-linux-arm64-master.tar.gz">Click here</a></td>
148148
</tr>
149149
<tr>
150150
<td>litmusctl-windows-386</td>
151+
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-1.24.0.tar.gz">Click here</a></td>
151152
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-1.23.0.tar.gz">Click here</a></td>
152153
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-1.22.0.tar.gz">Click here</a></td>
153154
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-1.21.0.tar.gz">Click here</a></td>
154155
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-1.20.0.tar.gz">Click here</a></td>
155156
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-1.19.0.tar.gz">Click here</a></td>
156157
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-1.18.0.tar.gz">Click here</a></td>
157158
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-1.17.0.tar.gz">Click here</a></td>
158-
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-1.16.0.tar.gz">Click here</a></td>
159159
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-386-master.tar.gz">Click here</a></td>
160160
</tr>
161161
<tr>
162162
<td>litmusctl-windows-amd64</td>
163+
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-1.24.0.tar.gz">Click here</a></td>
163164
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-1.23.0.tar.gz">Click here</a></td>
164165
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-1.22.0.tar.gz">Click here</a></td>
165166
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-1.21.0.tar.gz">Click here</a></td>
166167
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-1.20.0.tar.gz">Click here</a></td>
167168
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-1.19.0.tar.gz">Click here</a></td>
168169
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-1.18.0.tar.gz">Click here</a></td>
169170
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-1.17.0.tar.gz">Click here</a></td>
170-
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-1.16.0.tar.gz">Click here</a></td>
171171
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-amd64-master.tar.gz">Click here</a></td>
172172
</tr>
173173
<tr>
174174
<td>litmusctl-windows-arm</td>
175+
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-1.24.0.tar.gz">Click here</a></td>
175176
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-1.23.0.tar.gz">Click here</a></td>
176177
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-1.22.0.tar.gz">Click here</a></td>
177178
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-1.21.0.tar.gz">Click here</a></td>
178179
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-1.20.0.tar.gz">Click here</a></td>
179180
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-1.19.0.tar.gz">Click here</a></td>
180181
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-1.18.0.tar.gz">Click here</a></td>
181182
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-1.17.0.tar.gz">Click here</a></td>
182-
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-1.16.0.tar.gz">Click here</a></td>
183183
<td><a href="https://litmusctl-production-bucket.s3.amazonaws.com/litmusctl-windows-arm-master.tar.gz">Click here</a></td>
184184
</tr>
185185
</table>

pkg/utils/compatibility.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,6 @@ var (
4646
"1.21.0": {"3.0.0", "3.1.0", "3.2.0", "3.3.0", "3.4.0", "3.5.0", "3.6.0", "3.6.1", "3.7.0", "3.8.0", "3.9.0", "3.9.1", "3.10.0", "3.11.0", "3.12.0", "3.13.0", "3.14.0", "3.15.0", "3.16.0", "3.17.0", "3.18.0", "3.19.0", "3.20.0", "3.21.0", "3.22.0", "3.23.0", "3.24.0"},
4747
"1.22.0": {"3.0.0", "3.1.0", "3.2.0", "3.3.0", "3.4.0", "3.5.0", "3.6.0", "3.6.1", "3.7.0", "3.8.0", "3.9.0", "3.9.1", "3.10.0", "3.11.0", "3.12.0", "3.13.0", "3.14.0", "3.15.0", "3.16.0", "3.17.0", "3.18.0", "3.19.0", "3.20.0", "3.21.0", "3.22.0", "3.23.0", "3.24.0", "3.25.0"},
4848
"1.23.0": {"3.0.0", "3.1.0", "3.2.0", "3.3.0", "3.4.0", "3.5.0", "3.6.0", "3.6.1", "3.7.0", "3.8.0", "3.9.0", "3.9.1", "3.10.0", "3.11.0", "3.12.0", "3.13.0", "3.14.0", "3.15.0", "3.16.0", "3.17.0", "3.18.0", "3.19.0", "3.20.0", "3.21.0", "3.22.0", "3.23.0", "3.24.0", "3.25.0", "3.26.0"},
49+
"1.24.0": {"3.0.0", "3.1.0", "3.2.0", "3.3.0", "3.4.0", "3.5.0", "3.6.0", "3.6.1", "3.7.0", "3.8.0", "3.9.0", "3.9.1", "3.10.0", "3.11.0", "3.12.0", "3.13.0", "3.14.0", "3.15.0", "3.16.0", "3.17.0", "3.18.0", "3.19.0", "3.20.0", "3.21.0", "3.22.0", "3.23.0", "3.24.0", "3.25.0", "3.26.0", "3.27.0"},
4950
}
5051
)

script.py

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
"""LitmusChaos experiment lifecycle: pod selection, YAML rendering, start, and wait."""
2+
3+
import logging
4+
import random
5+
import tempfile
6+
import time
7+
from pathlib import Path
8+
9+
from kubernetes import client as k8s_client
10+
11+
from .helpers import get_service_nodeport, run, run_json
12+
13+
CHAOS_TEMPLATE = Path(__file__).resolve().parent.parent / "charts" / "chaos" / "client-experiment.yaml"
14+
15+
log = logging.getLogger(__name__)
16+
17+
18+
def select_target_pods(
19+
v1: k8s_client.CoreV1Api,
20+
namespace: str,
21+
pods_affected_perc: int,
22+
seed: int,
23+
) -> list[str]:
24+
"""Deterministically select a subset of client pods based on percentage and seed.
25+
26+
:param v1: Kubernetes CoreV1Api client
27+
:param namespace: Kubernetes namespace
28+
:param pods_affected_perc: Percentage of pods to target (1-100)
29+
:param seed: Random seed for reproducibility
30+
:return: List of selected pod names
31+
"""
32+
pods = v1.list_namespaced_pod(
33+
namespace,
34+
label_selector="app.kubernetes.io/component=fedn-client",
35+
)
36+
pod_names = sorted(p.metadata.name for p in pods.items if p.status.phase == "Running")
37+
38+
count = max(1, len(pod_names) * pods_affected_perc // 100)
39+
rng = random.Random(seed)
40+
selected = rng.sample(pod_names, min(count, len(pod_names)))
41+
log.info(
42+
"Selected %d/%d client pods (perc=%d%%, seed=%d): %s",
43+
len(selected), len(pod_names), pods_affected_perc, seed, selected,
44+
)
45+
return selected
46+
47+
48+
def render_chaos_yaml(target_pods: list[str]) -> Path:
49+
"""Read the chaos experiment template and fill in TARGET_PODS.
50+
51+
Returns the path to a temporary YAML file with the value substituted.
52+
"""
53+
content = CHAOS_TEMPLATE.read_text()
54+
content = content.replace("__TARGET_PODS__", ",".join(target_pods))
55+
tmp = tempfile.NamedTemporaryFile(
56+
mode="w", suffix=".yaml", prefix="chaos-experiment-", delete=False,
57+
)
58+
tmp.write(content)
59+
tmp.close()
60+
return Path(tmp.name)
61+
62+
63+
def start_chaos_experiment(
64+
v1: k8s_client.CoreV1Api,
65+
node_ip: str,
66+
namespace: str,
67+
litmus_namespace: str,
68+
target_pods: list[str],
69+
) -> tuple[str, str, Path] | None:
70+
"""Start the LitmusChaos pod-delete experiment. Returns (project_id, exp_id) or None."""
71+
chaos_port = get_service_nodeport(
72+
v1,
73+
"chaos-litmus-frontend-service",
74+
litmus_namespace,
75+
"http",
76+
)
77+
78+
run(
79+
[
80+
"litmusctl",
81+
"config",
82+
"set-account",
83+
"-n",
84+
"-e",
85+
f"http://{node_ip}:{chaos_port}",
86+
"-u",
87+
"admin",
88+
"-p",
89+
"litmus",
90+
]
91+
)
92+
93+
projects = run_json(["litmusctl", "get", "projects", "-o", "json"])
94+
project_id = projects["projects"][0]["projectID"]
95+
96+
infras = run_json(
97+
[
98+
"litmusctl",
99+
"get",
100+
"chaos-infra",
101+
"--project-id",
102+
project_id,
103+
"-o",
104+
"json",
105+
]
106+
)
107+
infra_id = infras["listInfras"]["infras"][0]["infraID"]
108+
109+
log.info("Project: %s Infra: %s", project_id, infra_id)
110+
111+
# Delete existing experiment so it can be recreated with updated parameters
112+
experiments = run_json(
113+
[
114+
"litmusctl",
115+
"get",
116+
"chaos-experiments",
117+
"--project-id",
118+
project_id,
119+
"-o",
120+
"json",
121+
]
122+
)
123+
existing = [e["experimentID"] for e in experiments["listExperiment"]["experiments"] if "client-experiment" in e.get("name", "")]
124+
125+
for old_id in existing:
126+
log.info("Deleting old chaos experiment %s...", old_id)
127+
run(
128+
[
129+
"litmusctl",
130+
"delete",
131+
"chaos-experiment",
132+
old_id,
133+
"--project-id",
134+
project_id,
135+
],
136+
check=False,
137+
)
138+
139+
# Create experiment from template with TARGET_PODS filled in
140+
log.info("Creating chaos experiment (target_pods=%s)...", target_pods)
141+
chaos_yaml = render_chaos_yaml(target_pods)
142+
log.debug("Rendered chaos YAML: %s", chaos_yaml)
143+
run(
144+
[
145+
"litmusctl",
146+
"create",
147+
"chaos-experiment",
148+
"-f",
149+
str(chaos_yaml),
150+
"--project-id",
151+
project_id,
152+
"--chaos-infra-id",
153+
infra_id,
154+
"-d",
155+
"client-experiment",
156+
]
157+
)
158+
159+
# Fetch the new experiment ID
160+
experiments = run_json(
161+
[
162+
"litmusctl",
163+
"get",
164+
"chaos-experiments",
165+
"--project-id",
166+
project_id,
167+
"-o",
168+
"json",
169+
]
170+
)
171+
existing = [e["experimentID"] for e in experiments["listExperiment"]["experiments"] if "client-experiment" in e.get("name", "")]
172+
exp_id = existing[0]
173+
174+
log.info("Running experiment %s...", exp_id)
175+
run(
176+
[
177+
"litmusctl",
178+
"run",
179+
"chaos-experiment",
180+
"--project-id",
181+
project_id,
182+
"--experiment-id",
183+
exp_id,
184+
]
185+
)
186+
187+
return project_id, exp_id, chaos_yaml
188+
189+
190+
def wait_for_chaos_experiment(
191+
project_id: str,
192+
exp_id: str,
193+
timeout: int,
194+
poll_interval: int,
195+
):
196+
"""Poll until the chaos experiment completes."""
197+
log.info("Waiting for chaos experiment to complete (timeout: %ds)...", timeout)
198+
elapsed = 0
199+
while elapsed < timeout:
200+
runs = run_json(
201+
[
202+
"litmusctl",
203+
"get",
204+
"chaos-experiment-runs",
205+
"--experiment-id",
206+
exp_id,
207+
"--project-id",
208+
project_id,
209+
"-o",
210+
"json",
211+
]
212+
)
213+
phase = runs["listExperimentRun"]["experimentRuns"][0]["phase"]
214+
215+
if phase == "Completed":
216+
log.info("Chaos experiment completed.")
217+
return
218+
219+
log.info(" Experiment phase: %s (%ds elapsed)...", phase, elapsed)
220+
time.sleep(poll_interval)
221+
elapsed += poll_interval
222+
223+
log.warning("Chaos experiment did not complete within %ds. Continuing anyway.", timeout)

0 commit comments

Comments
 (0)