ClickHouse/clickhouse-docs-embeddings huggingface dataset:
title_wip

[Edit this page](https://github.com/ClickHouse/clickhouse-docs/blob/main/docs/data-compression/compression-modes.md)

ClickHouse protocol supports **data blocks** compression with checksums.
Use `LZ4` if not sure what mode to pick.
``

Tip

Learn more about the [column compression codecs](/docs/sql-reference/statements/create/table#column_compression_codec) available and specify them when creating your tables, or afterward.

## Modes[​](#modes "Direct link to Modes")

|  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| value name description|  |  |  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | `0x02` [None](#none-mode) No compression, only checksums|  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | | `0x82` LZ4 Extremely fast, good compression|  |  |  | | --- | --- | --- | | `0x90` ZSTD Zstandard, pretty fast, best compression | | | | | | | | | | | |

Both LZ4 and ZSTD are made by same author, but with different tradeoffs.
From [Facebook benchmarks](https://facebook.github.io/zstd/#benchmarks):

|  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| name ratio encoding decoding|  |  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | --- | | **zstd** 1.4.5 -1 2.8 500 MB/s 1660 MB/s|  |  |  |  | | --- | --- | --- | --- | | **lz4** 1.9.2 2.1 740 MB/s 4530 MB/s | | | | | | | | | | | |

## Block[​](#block "Direct link to Block")

|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| field type description|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | checksum uint128 [Hash](/docs/native-protocol/hash) of (header + compressed data)| raw\_size uint32 Raw size without header|  |  |  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | --- | --- | | data\_size uint32 Uncompressed data size|  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | | mode byte Compression mode|  |  |  | | --- | --- | --- | | compressed\_data binary Block of compressed data | | | | | | | | | | | | | | | | | |

Header is (raw\_size + data\_size + mode), raw size consists of len(header + compressed\_data).

Checksum is `hash(header + compressed_data)`, using [ClickHouse CityHash](/docs/native-protocol/hash).

## None mode[​](#none-mode "Direct link to None mode")

If *None* mode is used, `compressed_data` is equal to original data.
No compression mode is useful to ensure additional data integrity with checksums, because
hashing overhead is negligible.

- [Modes](#modes)- [Block](#block)- [None mode](#none-mode)

Was this page helpful?
title_wip

[Edit this page](https://github.com/ClickHouse/clickhouse-docs/blob/main/docs/data-modeling/index.md)

This section is about data modeling in ClickHouse and contains the following topics:

|  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Page Description|  |  |  |  |  |  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | [Schema Design](/docs/data-modeling/schema-design) Discusses ClickHouse schema design for optimal performance, considering factors like queries, data updates, latency, and volume.|  |  |  |  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | [Dictionary](/docs/dictionary) An explainer on how to define and use dictionaries to improve query performance and enrich data.|  |  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | --- | | [Materialized Views](/docs/materialized-views) Information on Materialized Views and Refreshable Materialized Views in ClickHouse.|  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | | [Projections](/docs/data-modeling/projections) Information on Projections in ClickHouse.|  |  |  |  | | --- | --- | --- | --- | | [Data Compression](/docs/data-compression/compression-in-clickhouse) Discusses various compression modes in ClickHouse and how to optimize data storage and query performance by choosing the right compression method for your specific data types and workloads.|  |  | | --- | --- | | [Denormalizing Data](/docs/data-modeling/denormalization) Discusses the denormalization approach used in ClickHouse which aims to improve query performance by storing related data in a single table. | | | | | | | | | | | | | |

Was this page helpful?
Schema Design

--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | `ParentId` No - 20696028 Yes Consider Null to be an empty string String|  |  |  |  |  |  |  |  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | `CommunityOwnedDate` No 2008-08-12 04:59:35.017000000, 2024-04-01 05:36:41.380000000 - Yes Consider default 1970-01-01 for Nulls. Millisecond granularity isn't required, use DateTime DateTime|  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | | `ClosedDate` No 2008-09-04 20:56:44, 2024-04-06 18:49:25.393000000 - Yes Consider default 1970-01-01 for Nulls. Millisecond granularity isn't required, use DateTime DateTime | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | |
title_wip

[Edit this page](https://github.com/ClickHouse/clickhouse-docs/blob/main/docs/deployment-guides/index.md)

This section covers the following topics:

|  |  |  |  |  |
| --- | --- | --- | --- | --- |
| Topic|  |  |  |  | | --- | --- | --- | --- | | [Introduction](/docs/architecture/introduction)| [Scaling Out](/docs/architecture/horizontal-scaling)| [Replication for fault tolerance](/docs/architecture/replication)| [Cluster deployment](/docs/architecture/cluster-deployment) | | | | |

Was this page helpful?
Parallel Replicas

│ c-crimson-vd-86-server-16j1ncj-0 │ ParallelReplicasReadAssignedForStealingMarks   │     2 │ Sum across all replicas of how many of scheduled marks were assigned for stealing by consistent hash │
│ c-crimson-vd-86-server-16j1ncj-0 │ ParallelReplicasStealingByHashMicroseconds     │    10 │ Time spent collecting segments meant for stealing by hash                                            │
│ c-crimson-vd-86-server-16j1ncj-0 │ ParallelReplicasProcessingPartsMicroseconds    │     6 │ Time spent processing data parts                                                                     │
│ c-crimson-vd-86-server-16j1ncj-0 │ ParallelReplicasStealingLeftoversMicroseconds  │     2 │ Time spent collecting orphaned segments                                                              │
│ c-crimson-vd-86-server-16j1ncj-0 │ ParallelReplicasUsedCount                      │     2 │ Number of replicas used to execute a query with task-based parallel replicas                         │
│ c-crimson-vd-86-server-16j1ncj-0 │ ParallelReplicasAvailableCount                 │    12 │ Number of replicas available to execute a query with task-based parallel replicas                    │
└──────────────────────────────────┴────────────────────────────────────────────────┴───────┴──────────────────────────────────────────────────────────────────────────────────────────────────────┘
```
Parallel Replicas

The [`system.text_log`](/docs/operations/system-tables/text_log) table also
contains information about the execution of queries using parallel replicas:

```
SELECT message
FROM clusterAllReplicas('default', system.text_log)
WHERE query_id = 'ad40c712-d25d-45c4-b1a1-a28ba8d4019c'
ORDER BY event_time_microseconds ASC
```

Response
Parallel Replicas

Finally, you can also use the `EXPLAIN PIPELINE`. It highlights how ClickHouse
is going to execute a query and what resources are going to be used for the
execution of the query. Let's take the following query for example:

```
SELECT count(), uniq(pageId) , min(timestamp), max(timestamp) 
FROM session_events 
WHERE type='type3' 
GROUP BY toYear(timestamp) LIMIT 10
```

Let's have a look at the query pipeline without parallel replica:

```
EXPLAIN PIPELINE graph = 1, compact = 0 
SELECT count(), uniq(pageId) , min(timestamp), max(timestamp) 
FROM session_events 
WHERE type='type3' 
GROUP BY toYear(timestamp) 
LIMIT 10 
SETTINGS allow_experimental_parallel_reading_from_replicas=0 
FORMAT TSV;
```

And now with parallel replica:

```
EXPLAIN PIPELINE graph = 1, compact = 0 
SELECT count(), uniq(pageId) , min(timestamp), max(timestamp) 
FROM session_events 
WHERE type='type3' 
GROUP BY toYear(timestamp) 
LIMIT 10 
SETTINGS allow_experimental_parallel_reading_from_replicas=2 
FORMAT TSV;
```

- [Introduction](#introduction)- [Sharded architecture](#sharded-architecture)- [Non-sharded architecture](#non-sharded-architecture)- [Introducing parallel replicas](#introducing-parallel-replicas)
        - [Announcements](#announcements)- [Dynamic coordination](#dynamic-coordination)- [Managing cache locality](#managing-cache-locality)- [Task stealing](#task-stealing)- [Limitations](#limitations)- [Settings related to parallel replicas](#settings-related-to-parallel-replicas)- [Investigating issues with parallel replicas](#investigating-issues-with-parallel-replicas)

Was this page helpful?
title_wip

Replication is physical: only compressed parts are transferred between nodes, not queries. Merges are processed on each replica independently in most cases to lower the network costs by avoiding network amplification. Large merged parts are sent over the network only in cases of significant replication lag.

Besides, each replica stores its state in ZooKeeper as the set of parts and its checksums. When the state on the local filesystem diverges from the reference state in ZooKeeper, the replica restores its consistency by downloading missing and broken parts from other replicas. When there is some unexpected or broken data in the local filesystem, ClickHouse does not remove it, but moves it to a separate directory and forgets it.

Note

The ClickHouse cluster consists of independent shards, and each shard consists of replicas. The cluster is **not elastic**, so after adding a new shard, data is not rebalanced between shards automatically. Instead, the cluster load is supposed to be adjusted to be uneven. This implementation gives you more control, and it is ok for relatively small clusters, such as tens of nodes. But for clusters with hundreds of nodes that we are using in production, this approach becomes a significant drawback. We should implement a table engine that spans across the cluster with dynamically replicated regions that could be split and balanced between clusters automatically.

- [Columns](#columns)- [Field](#field)- [Leaky abstractions](#leaky-abstractions)- [Data types](#data_types)- [Block](#block)- [Processors](#processors)- [Formats](#formats)- [I/O](#io)- [Tables](#tables)- [Parsers](#parsers)- [Interpreters](#interpreters)- [Functions](#functions)- [Aggregate functions](#aggregate-functions)- [Server](#server)- [Configuration](#configuration)
                              - [Context](#context)- [Threads and jobs](#threads-and-jobs)- [Concurrency control](#concurrency-control)- [Distributed query execution](#distributed-query-execution)- [Merge tree](#merge-tree)- [Replication](#replication)

Was this page helpful?
title_wip

[Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/development/build-cross-arm.md)

No special steps are required to build ClickHouse for Aarch64 on an Aarch64 machine.

To cross compile ClickHouse for AArch64 on an x86 Linux machine, pass the following flag to `cmake`: `-DCMAKE_TOOLCHAIN_FILE=cmake/linux/toolchain-aarch64.cmake`

Was this page helpful?
title_wip

[Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/development/build-cross-loongarch.md)

ClickHouse has experimental support for LoongArch64

## Build ClickHouse[​](#build-clickhouse "Direct link to Build ClickHouse")

The llvm version required for building must be greater than or equal to 21.1.0.

```
cd ClickHouse
mkdir build-loongarch64
cmake . -Bbuild-loongarch64 -DCMAKE_TOOLCHAIN_FILE=cmake/linux/toolchain-loongarch64.cmake
ninja -C build-loongarch64
```

The resulting binary will run only on Linux with the LoongArch64 CPU architecture.

- [Build ClickHouse](#build-clickhouse)

Was this page helpful?
title_wip

[Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/development/build-cross-osx.md)

This is for the case when you have a Linux machine and want to use it to build `clickhouse` binary that will run on OS X.
The main use case is continuous integration checks which run on Linux machines.
If you want to build ClickHouse directly on macOS, proceed with the [native build instructions](/docs/development/build-osx).

The cross-build for macOS is based on the [Build instructions](/docs/development/build), follow them first.

The following sections provide a walk-through for building ClickHouse for `x86_64` macOS.
If you're targeting ARM architecture, simply substitute all occurrences of `x86_64` with `aarch64`.
For example, replace `x86_64-apple-darwin` with `aarch64-apple-darwin` throughout the steps.

## Install cross-compilation toolset[​](#install-cross-compilation-toolset "Direct link to Install cross-compilation toolset")

Let's remember the path where we install `cctools` as `${CCTOOLS}`

```
mkdir ~/cctools
export CCTOOLS=$(cd ~/cctools && pwd)
cd ${CCTOOLS}

git clone https://github.com/tpoechtrager/apple-libtapi.git
cd apple-libtapi
git checkout 15dfc2a8c9a2a89d06ff227560a69f5265b692f9
INSTALLPREFIX=${CCTOOLS} ./build.sh
./install.sh
cd ..

git clone https://github.com/tpoechtrager/cctools-port.git
cd cctools-port/cctools
git checkout 2a3e1c2a6ff54a30f898b70cfb9ba1692a55fad7
./configure --prefix=$(readlink -f ${CCTOOLS}) --with-libtapi=$(readlink -f ${CCTOOLS}) --target=x86_64-apple-darwin
make install
```

Also, we need to download macOS X SDK into the working tree.

```
cd ClickHouse/cmake/toolchain/darwin-x86_64
curl -L 'https://github.com/phracker/MacOSX-SDKs/releases/download/11.3/MacOSX11.0.sdk.tar.xz' | tar xJ --strip-components=1
```

## Build ClickHouse[​](#build-clickhouse "Direct link to Build ClickHouse")

```
cd ClickHouse
mkdir build-darwin
cd build-darwin
cmake -DCMAKE_AR:FILEPATH=${CCTOOLS}/bin/x86_64-apple-darwin-ar -DCMAKE_INSTALL_NAME_TOOL=${CCTOOLS}/bin/x86_64-apple-darwin-install_name_tool -DCMAKE_RANLIB:FILEPATH=${CCTOOLS}/bin/x86_64-apple-darwin-ranlib -DLINKER_NAME=${CCTOOLS}/bin/x86_64-apple-darwin-ld -DCMAKE_TOOLCHAIN_FILE=cmake/darwin/toolchain-x86_64.cmake ..
ninja
```

The resulting binary will have a Mach-O executable format and can't be run on Linux.

- [Install cross-compilation toolset](#install-cross-compilation-toolset)- [Build ClickHouse](#build-clickhouse)

Was this page helpful?
title_wip

[Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/development/build-cross-riscv.md)

ClickHouse has experimental support for RISC-V. Not all features can be enabled.

## Build ClickHouse[​](#build-clickhouse "Direct link to Build ClickHouse")

To cross-compile for RISC-V on an non-RISC-V machine:

```
cd ClickHouse
mkdir build-riscv64
cmake . -Bbuild-riscv64 -G Ninja -DCMAKE_TOOLCHAIN_FILE=cmake/linux/toolchain-riscv64.cmake -DGLIBC_COMPATIBILITY=OFF -DENABLE_LDAP=OFF  -DOPENSSL_NO_ASM=ON -DENABLE_JEMALLOC=ON -DENABLE_PARQUET=OFF -DENABLE_GRPC=OFF -DENABLE_HDFS=OFF -DENABLE_MYSQL=OFF
ninja -C build-riscv64
```

The resulting binary will run only on Linux with the RISC-V 64 CPU architecture.

- [Build ClickHouse](#build-clickhouse)

Was this page helpful?
title_wip

[Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/development/build-e2k.md)

ClickHouse has experimental support for E2K (Elbrus-2000), and can only be compiled in native mode with minimal configuration using e2k custom-built libraries such as boost, jemalloc, libunwind, zstd.

## Build ClickHouse[​](#build-clickhouse "Direct link to Build ClickHouse")

The llvm version required for building must be greater than or equal to 20.1.8.

```
cd ClickHouse
mkdir build-e2k
cmake -DCMAKE_CROSSCOMPILING=OFF -DCOMPILER_CACHE=disabled \
 -DCMAKE_C_COMPILER=/usr/lib/llvm-20/bin/clang -DCMAKE_CXX_COMPILER=/usr/lib/llvm-20/bin/clang++ \
 -DLLD_PATH=/usr/lib/llvm-20/bin/ld.lld \
 -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr \
 -DGLIBC_COMPATIBILITY=OFF -DENABLE_LIBRARIES=OFF -DWERROR=OFF \
 -DENABLE_SSL=OFF -DENABLE_OPENSSL_DYNAMIC=ON \
 -DUSE_SIMDJSON=OFF -DENABLE_JEMALLOC=OFF -DENABLE_TESTS=OFF -DUSE_SYSTEM_COMPILER_RT=OFF \
 -DBOOST_USE_UCONTEXT=ON -DENABLE_NURAFT=ON -DENABLE_RAPIDJSON=ON -DUSE_LIBFIU=ON ..
ninja -j8
```

The resulting binary will run only on Linux with the E2K CPU architecture.

- [Build ClickHouse](#build-clickhouse)

Was this page helpful?
title_wip

[Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/engines/index.md)

|  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- |
| Page Description|  |  |  |  | | --- | --- | --- | --- | | [Database Engines](/docs/engines/database-engines) Database engines in ClickHouse allow you to work with tables and determine how data is stored and managed. Learn more about the various database engines available in ClickHouse.|  |  | | --- | --- | | [Table Engines](/docs/engines/table-engines) Table engines in ClickHouse are a fundamental concept that determines how data is stored, written, and read. Learn more about the various table engines available in ClickHouse. | | | | | |

Was this page helpful?
title_wip

[Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/engines/database-engines/index.md)

Database engines allow you to work with tables. By default, ClickHouse uses the [Atomic](/docs/engines/database-engines/atomic) database engine, which provides configurable [table engines](/docs/engines/table-engines) and an [SQL dialect](/docs/sql-reference/syntax).

Here is a complete list of available database engines. Follow the links for more details:

|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| Page Description|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | [Atomic](/docs/engines/database-engines/atomic) The `Atomic` engine supports non-blocking `DROP TABLE` and `RENAME TABLE` queries, and atomic `EXCHANGE TABLES`queries. The `Atomic` database engine is used by default.| [Shared](/docs/engines/database-engines/shared) Page describing the `Shared` database engine, available in ClickHouse Cloud| [Replicated](/docs/engines/database-engines/replicated) The engine is based on the Atomic engine. It supports replication of metadata via DDL log being written to ZooKeeper and executed on all of the replicas for a given database.|  |  |  |  |  |  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | [PostgreSQL](/docs/engines/database-engines/postgresql) Allows to connect to databases on a remote PostgreSQL server.|  |  |  |  |  |  |  |  |  |  | | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | [MySQL](/docs/engines/database-engines/mysql) Allows connecting to databases on a remote MySQL server and perform `INSERT` and `SELECT` queries to exchange data between ClickHouse and MySQL.| [SQLite](/docs/engines/database-engines/sqlite) Allows to connect to SQLite databases and perform `INSERT` and `SELECT` queries to exchange data between ClickHouse and SQLite.| [Backup](/docs/engines/database-engines/backup) Allows to instantly attach table/database from backups in read-only mode.|  |  |  |  | | --- | --- | --- | --- | | [MaterializedPostgreSQL](/docs/engines/database-engines/materialized-postgresql) Creates a ClickHouse database with tables from PostgreSQL database.|  |  | | --- | --- | | [DataLakeCatalog](/docs/engines/database-engines/datalakecatalog) The DataLakeCatalog database engine enables you to connect ClickHouse to external data catalogs and query open table format data | | | | | | | | | | | | | | | | | | | |

Was this page helpful?
title_wip

[Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/engines/database-engines/shared.md)

ClickHouse Cloud only

The `Shared` database engine works in conjunction with Shared Catalog to manage databases whose tables use stateless table engines such as [`SharedMergeTree`](/docs/cloud/reference/shared-merge-tree).
These table engines do not write persistent state to disk and are compatible with dynamic compute environments.

The `Shared` database engine in Cloud removes the dependency for local disks.
It is a purely in-memory engine, requiring only CPU and memory.

## How does it work?[​](#how-it-works "Direct link to How does it work?")

The `Shared` database engine stores all database and table definitions in a central Shared Catalog backed by Keeper. Instead of writing to local disk, it maintains a single versioned global state shared across all compute nodes.

Each node tracks only the last applied version and, on startup, fetches the latest state without the need for local files or manual setup.

## Syntax[​](#syntax "Direct link to Syntax")

For end users, using Shared Catalog and the Shared database engine requires no additional configuration. Database creation is the same as always:

```
CREATE DATABASE my_database;
```

ClickHouse Cloud automatically assigns the Shared database engine to databases. Any tables created within such a database using stateless engines will automatically benefit from Shared Catalog’s replication and coordination capabilities.

Tip

For more information on Shared Catalog and it's benefits, see ["Shared catalog and shared database engine"](/docs/cloud/reference/shared-catalog) in the Cloud reference section.

- [How does it work?](#how-it-works)- [Syntax](#syntax)

Was this page helpful?
title_wip

[Edit this page](https://github.com/ClickHouse/ClickHouse/tree/master/docs/en/engines/table-engines/integrations/index.md)

ClickHouse provides various means for integrating with external systems, including table engines. Like with all other table engines, the configuration is done using `CREATE TABLE` or `ALTER TABLE` queries. Then from a user perspective, the configured integration looks like a normal table, but queries to it are proxied to the external system. This transparent querying is one of the key advantages of this approach over alternative integration methods, like dictionaries or table functions, which require the use of custom query methods on each use.
title_wip

|  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |  |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |