Skip to content

Commit 0957bab

Browse files
authored
Merge pull request #1640 from atheo89/sync-konflux
RHAIENG-1504: incorporate changes to .konflux dockerfiles
2 parents e746416 + b06a26e commit 0957bab

File tree

19 files changed

+216
-101
lines changed

19 files changed

+216
-101
lines changed

jupyter/datascience/ubi9-python-3.12/Dockerfile.konflux.cpu

Lines changed: 40 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#########################
44
ARG BASE_IMAGE
55

6+
# External image alias for UBI repository configuration
7+
FROM registry.access.redhat.com/ubi9/ubi AS ubi-repos
8+
69
######################################################
710
# mongocli-builder (build stage only, not published) #
811
######################################################
@@ -20,7 +23,7 @@ RUN arch="${TARGETARCH:-$(uname -m)}" && \
2023
arch=$(echo "$arch" | cut -d- -f1) && \
2124
if [ "$arch" = "s390x" ]; then \
2225
echo "Skipping mongocli build for ${arch}, creating dummy binary"; \
23-
mkdir -p /tmp && echo -e '#!/bin/sh\necho "mongocli not supported on s390x"' > /tmp/mongocli && \
26+
mkdir -p /tmp && printf '#!/bin/sh\necho "mongocli not supported on s390x"\n' > /tmp/mongocli && \
2427
chmod +x /tmp/mongocli; \
2528
else \
2629
echo "Building mongocli for ${arch}"; \
@@ -44,7 +47,7 @@ ARG TARGETARCH
4447
# Inject the official UBI 9 repository configuration into the AIPCC base image.
4548
# The Quay-based AIPCC image is "repo-less" by default (https://gitlab.com/redhat/rhel-ai/core/base-images/app#repositories), so dnf cannot upgrade or install packages.
4649
# By copying ubi.repo from the public UBI 9 image, we enable package management for upgrades and installations.
47-
COPY --from=registry.access.redhat.com/ubi9/ubi /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
50+
COPY --from=ubi-repos /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
4851

4952
# upgrade first to avoid fixable vulnerabilities begin
5053
# Problem: The operation would result in removing the following protected packages: systemd
@@ -66,27 +69,35 @@ RUN --mount=type=cache,target=/var/cache/dnf \
6669
dnf install -y $PACKAGES && \
6770
dnf clean all && rm -rf /var/cache/yum
6871

69-
RUN if [ "$TARGETARCH" = "s390x" ]; then \
72+
RUN /bin/bash <<'EOF'
73+
set -Eeuxo pipefail
74+
if [ "$TARGETARCH" = "s390x" ]; then
7075
# Install Rust and set up environment
71-
mkdir -p /opt/.cargo && \
72-
export HOME=/root && \
73-
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup-init.sh && \
74-
chmod +x rustup-init.sh && \
75-
CARGO_HOME=/opt/.cargo HOME=/root ./rustup-init.sh -y --no-modify-path && \
76-
rm -f rustup-init.sh && \
77-
chown -R 1001:0 /opt/.cargo && \
76+
mkdir -p /opt/.cargo
77+
export HOME=/root
78+
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs -o rustup-init.sh
79+
chmod +x rustup-init.sh
80+
CARGO_HOME=/opt/.cargo HOME=/root ./rustup-init.sh -y --no-modify-path
81+
rm -f rustup-init.sh
82+
chown -R 1001:0 /opt/.cargo
7883
# Set environment variables
79-
echo 'export PATH=/opt/.cargo/bin:$PATH' >> /etc/profile.d/cargo.sh && \
80-
echo 'export CARGO_HOME=/opt/.cargo' >> /etc/profile.d/cargo.sh && \
81-
echo 'export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1' >> /etc/profile.d/cargo.sh; \
84+
cat > /etc/profile.d/cargo.sh <<'CARGO_EOF'
85+
export PATH=/opt/.cargo/bin:$PATH
86+
export CARGO_HOME=/opt/.cargo
87+
export GRPC_PYTHON_BUILD_SYSTEM_OPENSSL=1
88+
CARGO_EOF
8289
fi
90+
EOF
8391

8492
# Set python alternatives only for s390x (not needed for other arches)
85-
RUN if [ "$TARGETARCH" = "s390x" ]; then \
86-
alternatives --install /usr/bin/python python /usr/bin/python3.12 1 && \
87-
alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1 && \
88-
python --version && python3 --version; \
93+
RUN /bin/bash <<'EOF'
94+
set -Eeuxo pipefail
95+
if [ "$TARGETARCH" = "s390x" ]; then
96+
alternatives --install /usr/bin/python python /usr/bin/python3.12 1
97+
alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1
98+
python --version && python3 --version
8999
fi
100+
EOF
90101

91102
# Other apps and tools installed as default user
92103
USER 1001
@@ -109,6 +120,7 @@ RUN curl -L https://mirror.openshift.com/pub/openshift-v4/$(uname -m)/clients/oc
109120
FROM cpu-base AS pyarrow-builder
110121

111122
ARG TARGETARCH
123+
# hadolint ignore=DL3002
112124
USER 0
113125
WORKDIR /tmp/build-wheels
114126

@@ -167,8 +179,9 @@ RUN --mount=type=cache,target=/root/.cache/pip \
167179
#######################################################
168180
FROM cpu-base AS common-builder
169181
ARG TARGETARCH
182+
# hadolint ignore=DL3002
170183
USER root
171-
RUN <<'EOF'
184+
RUN /bin/bash <<'EOF'
172185
set -Eeuxo pipefail
173186
if [ "${TARGETARCH}" = "ppc64le" ]; then
174187
dnf install -y gcc-toolset-13 cmake ninja-build git wget unzip
@@ -193,8 +206,9 @@ if [ "${TARGETARCH}" = "ppc64le" ]; then
193206
cd onnx
194207
git checkout ${ONNX_VERSION}
195208
git submodule update --init --recursive
196-
pip install -r requirements.txt
197-
export CMAKE_ARGS="-DPython3_EXECUTABLE=$(which python3.12)"
209+
pip install --no-cache-dir -r requirements.txt
210+
CMAKE_ARGS="-DPython3_EXECUTABLE=$(which python3.12)"
211+
export CMAKE_ARGS
198212
pip wheel . -w /root/onnx_wheel
199213
else
200214
echo "Skipping ONNX build on non-Power"
@@ -212,7 +226,7 @@ WORKDIR /root
212226
RUN <<'EOF'
213227
set -Eeuxo pipefail
214228
if [ "${TARGETARCH}" = "ppc64le" ]; then
215-
wget https://github.com/OpenMathLib/OpenBLAS/releases/download/v${OPENBLAS_VERSION}/OpenBLAS-${OPENBLAS_VERSION}.zip
229+
wget --progress=dot:giga https://github.com/OpenMathLib/OpenBLAS/releases/download/v${OPENBLAS_VERSION}/OpenBLAS-${OPENBLAS_VERSION}.zip
216230
unzip OpenBLAS-${OPENBLAS_VERSION}.zip
217231
cd OpenBLAS-${OPENBLAS_VERSION}
218232
make -j$(nproc) TARGET=POWER9 BINARY=64 USE_OPENMP=1 USE_THREAD=1 NUM_THREADS=120 DYNAMIC_ARCH=1 INTERFACE64=0
@@ -221,6 +235,7 @@ else
221235
echo "Skipping OpenBLAS build on non-Power"
222236
fi
223237
EOF
238+
224239
####################
225240
# jupyter-minimal #
226241
####################
@@ -296,17 +311,17 @@ COPY --from=openblas-builder /root/OpenBLAS-${OPENBLAS_VERSION} /openblas
296311
COPY --from=onnx-builder /root/onnx_wheel/ /onnxwheels/
297312

298313
# Power-specific ONNX/OpenBLAS installation
299-
RUN <<'EOF'
314+
RUN /bin/bash <<'EOF'
300315
set -Eeuxo pipefail
301316
if [ "${TARGETARCH}" = "ppc64le" ]; then
302-
pip install /onnxwheels/*.whl
317+
pip install --no-cache-dir /onnxwheels/*.whl
303318
else
304319
echo "Skipping ONNX/OpenBLAS install on non-Power"
305320
fi
306321
EOF
307322

308323
USER root
309-
RUN <<'EOF'
324+
RUN /bin/bash <<'EOF'
310325
set -Eeuxo pipefail
311326
if [ "${TARGETARCH}" = "ppc64le" ]; then
312327
rm -rf /onnxwheels
@@ -315,7 +330,7 @@ else
315330
fi
316331
EOF
317332

318-
RUN <<'EOF'
333+
RUN /bin/bash <<'EOF'
319334
set -Eeuxo pipefail
320335
if [ "${TARGETARCH}" = "ppc64le" ]; then
321336
PREFIX=/usr/local make -C /openblas install

jupyter/minimal/ubi9-python-3.12/Dockerfile.cpu

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,24 @@ ARG BASE_IMAGE
66
# External image alias for UBI repository configuration
77
FROM registry.access.redhat.com/ubi9/ubi AS ubi-repos
88

9+
############################
10+
# Stage 1: PDF Tool Build #
11+
############################
12+
FROM registry.access.redhat.com/ubi9/python-312:latest AS pdf-builder
13+
14+
WORKDIR /opt/app-root/bin
15+
16+
# OS Packages needs to be installed as root
17+
USER 0
18+
19+
# Copy scripts
20+
COPY jupyter/utils/install_texlive.sh ./install_texlive.sh
21+
COPY jupyter/utils/install_pandoc.sh ./install_pandoc.sh
22+
RUN chmod +x install_texlive.sh install_pandoc.sh
23+
24+
RUN ./install_texlive.sh
25+
RUN ./install_pandoc.sh
26+
927
####################
1028
# cpu-base #
1129
####################
@@ -71,9 +89,14 @@ COPY ${JUPYTER_REUSABLE_UTILS} utils/
7189
USER 0
7290

7391
# Dependencies for PDF export begin
74-
RUN ./utils/install_pdf_deps.sh
75-
ENV PATH="/usr/local/texlive/bin/linux:/usr/local/pandoc/bin:$PATH"
76-
# Dependencies for PDF export end
92+
RUN --mount=type=cache,from=pdf-builder,source=/usr/local/,target=/pdf_builder/,rw \
93+
bash -c ' \
94+
if [[ "$(uname -m)" == "ppc64le" ]]; then \
95+
cp -r /pdf_builder/texlive /usr/local/; \
96+
cp -r /pdf_builder/pandoc /usr/local/; \
97+
else \
98+
./utils/install_pdf_deps.sh; \
99+
fi'
77100

78101
USER 1001
79102

jupyter/minimal/ubi9-python-3.12/Dockerfile.konflux.cpu

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#########################
44
ARG BASE_IMAGE
55

6+
# External image alias for UBI repository configuration
7+
FROM registry.access.redhat.com/ubi9/ubi AS ubi-repos
8+
69
############################
710
# Stage 1: PDF Tool Build #
811
############################
@@ -34,7 +37,7 @@ USER 0
3437
# Inject the official UBI 9 repository configuration into the AIPCC base image.
3538
# The Quay-based AIPCC image is "repo-less" by default (https://gitlab.com/redhat/rhel-ai/core/base-images/app#repositories), so dnf cannot upgrade or install packages.
3639
# By copying ubi.repo from the public UBI 9 image, we enable package management for upgrades and installations.
37-
COPY --from=registry.access.redhat.com/ubi9/ubi /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
40+
COPY --from=ubi-repos /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
3841

3942
# upgrade first to avoid fixable vulnerabilities begin
4043
# Problem: The operation would result in removing the following protected packages: systemd
@@ -69,28 +72,21 @@ FROM cpu-base AS jupyter-minimal
6972
ARG JUPYTER_REUSABLE_UTILS=jupyter/utils
7073
ARG MINIMAL_SOURCE_CODE=jupyter/minimal/ubi9-python-3.12
7174

72-
LABEL name="odh-notebook-jupyter-minimal-ubi9-python-3.12" \
73-
summary="Minimal Jupyter notebook image for ODH notebooks" \
74-
description="Minimal Jupyter notebook image with base Python 3.12 builder image based on UBI9 for ODH notebooks" \
75-
io.k8s.display-name="Minimal Jupyter notebook image for ODH notebooks" \
76-
io.k8s.description="Minimal Jupyter notebook image with base Python 3.12 builder image based on UBI9 for ODH notebooks" \
77-
authoritative-source-url="https://github.com/opendatahub-io/notebooks" \
78-
io.openshift.build.commit.ref="main" \
79-
io.openshift.build.source-location="https://github.com/opendatahub-io/notebooks/tree/main/jupyter/minimal/ubi9-python-3.12" \
80-
io.openshift.build.image="quay.io/opendatahub/workbench-images:jupyter-minimal-ubi9-python-3.12" \
81-
com.redhat.component="odh-workbench-jupyter-minimal-cpu-py312-rhel9" \
82-
com.redhat.license_terms="https://www.redhat.com/licenses/Red_Hat_Standard_EULA_20191108.pdf"
83-
8475
WORKDIR /opt/app-root/bin
8576

8677
COPY ${JUPYTER_REUSABLE_UTILS} utils/
8778

8879
USER 0
8980

9081
# Dependencies for PDF export begin
91-
RUN ./utils/install_pdf_deps.sh
92-
ENV PATH="/usr/local/texlive/bin/linux:/usr/local/pandoc/bin:$PATH"
93-
# Dependencies for PDF export end
82+
RUN --mount=type=cache,from=pdf-builder,source=/usr/local/,target=/pdf_builder/,rw \
83+
bash -c ' \
84+
if [[ "$(uname -m)" == "ppc64le" ]]; then \
85+
cp -r /pdf_builder/texlive /usr/local/; \
86+
cp -r /pdf_builder/pandoc /usr/local/; \
87+
else \
88+
./utils/install_pdf_deps.sh; \
89+
fi'
9490

9591
USER 1001
9692

@@ -116,3 +112,11 @@ RUN echo "Installing softwares and packages" && \
116112
WORKDIR /opt/app-root/src
117113

118114
ENTRYPOINT ["start-notebook.sh"]
115+
116+
LABEL name="rhoai/odh-workbench-jupyter-minimal-cpu-py312-rhel9" \
117+
com.redhat.component="odh-workbench-jupyter-minimal-cpu-py312-rhel9" \
118+
io.k8s.display-name="odh-workbench-jupyter-minimal-cpu-py312-rhel9" \
119+
summary="Minimal Jupyter CPU notebook image for ODH notebooks" \
120+
description="Minimal Jupyter CPU notebook image with base Python 3.12 builder image based on UBI9 for ODH notebooks" \
121+
io.k8s.description="Minimal Jupyter CPU notebook image with base Python 3.12 builder image based on UBI9 for ODH notebooks" \
122+
com.redhat.license_terms="https://www.redhat.com/licenses/Red_Hat_Standard_EULA_20191108.pdf"

jupyter/minimal/ubi9-python-3.12/Dockerfile.konflux.cuda

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ ARG TARGETARCH
55
#########################
66
ARG BASE_IMAGE
77

8+
# External image alias for UBI repository configuration
9+
FROM registry.access.redhat.com/ubi9/ubi AS ubi-repos
10+
811
####################
912
# cuda-base #
1013
####################
@@ -18,7 +21,7 @@ USER 0
1821
# Inject the official UBI 9 repository configuration into the AIPCC base image.
1922
# The Quay-based AIPCC image is "repo-less" by default (https://gitlab.com/redhat/rhel-ai/core/base-images/app#repositories), so dnf cannot upgrade or install packages.
2023
# By copying ubi.repo from the public UBI 9 image, we enable package management for upgrades and installations.
21-
COPY --from=registry.access.redhat.com/ubi9/ubi /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
24+
COPY --from=ubi-repos /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
2225

2326
# upgrade first to avoid fixable vulnerabilities begin
2427
# Problem: The operation would result in removing the following protected packages: systemd

jupyter/minimal/ubi9-python-3.12/Dockerfile.konflux.rocm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#########################
44
ARG BASE_IMAGE
55

6+
# External image alias for UBI repository configuration
7+
FROM registry.access.redhat.com/ubi9/ubi AS ubi-repos
8+
69
####################
710
# rocm-base #
811
####################
@@ -16,7 +19,7 @@ USER 0
1619
# Inject the official UBI 9 repository configuration into the AIPCC base image.
1720
# The Quay-based AIPCC image is "repo-less" by default (https://gitlab.com/redhat/rhel-ai/core/base-images/app#repositories), so dnf cannot upgrade or install packages.
1821
# By copying ubi.repo from the public UBI 9 image, we enable package management for upgrades and installations.
19-
COPY --from=registry.access.redhat.com/ubi9/ubi /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
22+
COPY --from=ubi-repos /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
2023

2124
# upgrade first to avoid fixable vulnerabilities begin
2225
# Problem: The operation would result in removing the following protected packages: systemd

jupyter/pytorch+llmcompressor/ubi9-python-3.12/Dockerfile.konflux.cuda

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ ARG TARGETARCH
55
#########################
66
ARG BASE_IMAGE
77

8+
# External image alias for UBI repository configuration
9+
FROM registry.access.redhat.com/ubi9/ubi AS ubi-repos
10+
811
######################################################
912
# mongocli-builder (build stage only, not published) #
1013
######################################################
@@ -31,7 +34,7 @@ USER 0
3134
# Inject the official UBI 9 repository configuration into the AIPCC base image.
3235
# The Quay-based AIPCC image is "repo-less" by default (https://gitlab.com/redhat/rhel-ai/core/base-images/app#repositories), so dnf cannot upgrade or install packages.
3336
# By copying ubi.repo from the public UBI 9 image, we enable package management for upgrades and installations.
34-
COPY --from=registry.access.redhat.com/ubi9/ubi /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
37+
COPY --from=ubi-repos /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
3538

3639
# upgrade first to avoid fixable vulnerabilities begin
3740
# Problem: The operation would result in removing the following protected packages: systemd

jupyter/pytorch/ubi9-python-3.12/Dockerfile.konflux.cuda

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ ARG TARGETARCH
55
#########################
66
ARG BASE_IMAGE
77

8+
# External image alias for UBI repository configuration
9+
FROM registry.access.redhat.com/ubi9/ubi AS ubi-repos
10+
811
######################################################
912
# mongocli-builder (build stage only, not published) #
1013
######################################################
@@ -31,7 +34,7 @@ USER 0
3134
# Inject the official UBI 9 repository configuration into the AIPCC base image.
3235
# The Quay-based AIPCC image is "repo-less" by default (https://gitlab.com/redhat/rhel-ai/core/base-images/app#repositories), so dnf cannot upgrade or install packages.
3336
# By copying ubi.repo from the public UBI 9 image, we enable package management for upgrades and installations.
34-
COPY --from=registry.access.redhat.com/ubi9/ubi /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
37+
COPY --from=ubi-repos /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
3538

3639
# upgrade first to avoid fixable vulnerabilities begin
3740
# Problem: The operation would result in removing the following protected packages: systemd

jupyter/rocm/pytorch/ubi9-python-3.12/Dockerfile.konflux.rocm

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#########################
44
ARG BASE_IMAGE
55

6+
# External image alias for UBI repository configuration
7+
FROM registry.access.redhat.com/ubi9/ubi AS ubi-repos
8+
69
######################################################
710
# mongocli-builder (build stage only, not published) #
811
######################################################
@@ -29,7 +32,7 @@ USER 0
2932
# Inject the official UBI 9 repository configuration into the AIPCC base image.
3033
# The Quay-based AIPCC image is "repo-less" by default (https://gitlab.com/redhat/rhel-ai/core/base-images/app#repositories), so dnf cannot upgrade or install packages.
3134
# By copying ubi.repo from the public UBI 9 image, we enable package management for upgrades and installations.
32-
COPY --from=registry.access.redhat.com/ubi9/ubi /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
35+
COPY --from=ubi-repos /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
3336

3437
# upgrade first to avoid fixable vulnerabilities begin
3538
# Problem: The operation would result in removing the following protected packages: systemd

jupyter/rocm/tensorflow/ubi9-python-3.12/Dockerfile.konflux.rocm

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
#########################
44
ARG BASE_IMAGE
55

6+
# External image alias for UBI repository configuration
7+
FROM registry.access.redhat.com/ubi9/ubi AS ubi-repos
8+
69
######################################################
710
# mongocli-builder (build stage only, not published) #
811
######################################################
@@ -29,7 +32,7 @@ USER 0
2932
# Inject the official UBI 9 repository configuration into the AIPCC base image.
3033
# The Quay-based AIPCC image is "repo-less" by default (https://gitlab.com/redhat/rhel-ai/core/base-images/app#repositories), so dnf cannot upgrade or install packages.
3134
# By copying ubi.repo from the public UBI 9 image, we enable package management for upgrades and installations.
32-
COPY --from=registry.access.redhat.com/ubi9/ubi /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
35+
COPY --from=ubi-repos /etc/yum.repos.d/ubi.repo /etc/yum.repos.d/ubi.repo
3336

3437
# upgrade first to avoid fixable vulnerabilities begin
3538
# Problem: The operation would result in removing the following protected packages: systemd
@@ -114,6 +117,7 @@ WORKDIR /opt/app-root/src
114117
###########################
115118
FROM rocm-jupyter-datascience AS rocm-jupyter-tensorflow
116119

120+
ARG JUPYTER_REUSABLE_UTILS=jupyter/utils
117121
ARG DATASCIENCE_SOURCE_CODE=jupyter/datascience/ubi9-python-3.12
118122
ARG TENSORFLOW_SOURCE_CODE=jupyter/rocm/tensorflow/ubi9-python-3.12
119123

@@ -145,6 +149,8 @@ RUN chmod -R g+w /opt/app-root/lib/python3.12/site-packages && \
145149
fix-permissions /opt/app-root -P
146150
USER 1001
147151

152+
COPY ${JUPYTER_REUSABLE_UTILS}/usercustomize.pth ${JUPYTER_REUSABLE_UTILS}/monkey_patch_protobuf_6x.py /opt/app-root/lib/python3.12/site-packages/
153+
148154
WORKDIR /opt/app-root/src
149155

150156
LABEL name="rhoai/odh-workbench-jupyter-tensorflow-rocm-py312-rhel9" \

0 commit comments

Comments
 (0)