From 8da1a9a3708af57390699e4645df50d80f995737 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Tue, 7 Nov 2023 15:48:07 +0800 Subject: [PATCH 01/88] [pipeline](fix) remove unreasonable CHECK (#26504) --- be/src/pipeline/exec/exchange_sink_buffer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/be/src/pipeline/exec/exchange_sink_buffer.cpp b/be/src/pipeline/exec/exchange_sink_buffer.cpp index 6003d41b5d5140..577eb4a46224fe 100644 --- a/be/src/pipeline/exec/exchange_sink_buffer.cpp +++ b/be/src/pipeline/exec/exchange_sink_buffer.cpp @@ -52,7 +52,6 @@ void BroadcastPBlockHolder::unref() noexcept { auto old_value = _ref_count._value.fetch_sub(1); if (_dep && old_value == 1) { _dep->return_available_block(); - CHECK(available()); } } From efd1aa3016eb91e01c1195998ea73a6dc087318d Mon Sep 17 00:00:00 2001 From: Mingyu Chen Date: Tue, 7 Nov 2023 16:37:24 +0800 Subject: [PATCH 02/88] [Revert](code-style) revert FE code-format #25033 and #26488 (#26505) --- .../{codestyle.yaml => checkstyle.yaml} | 8 +- .../developer-guide/java-format-code.md | 12 +- .../developer-guide/java-format-code.md | 20 +- .../checkstyle-apache-header.txt} | 3 +- fe/check/checkstyle/checkstyle.xml | 22 +- fe/check/checkstyle/import-control.xml | 5 +- fe/check/checkstyle/suppressions.xml | 8 +- fe/pom.xml | 463 ++++++++---------- 8 files changed, 256 insertions(+), 285 deletions(-) rename .github/workflows/{codestyle.yaml => checkstyle.yaml} (90%) rename fe/check/{spotless/copyright.txt => checkstyle/checkstyle-apache-header.txt} (97%) diff --git a/.github/workflows/codestyle.yaml b/.github/workflows/checkstyle.yaml similarity index 90% rename from .github/workflows/codestyle.yaml rename to .github/workflows/checkstyle.yaml index f2bd1bebf0ab73..13ab46b2cd50b2 100644 --- a/.github/workflows/codestyle.yaml +++ b/.github/workflows/checkstyle.yaml @@ -27,11 +27,10 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v3 with: persist-credentials: false submodules: recursive - fetch-depth: 0 - name: Paths Filter uses: ./.github/actions/paths-filter @@ -49,7 +48,8 @@ jobs: with: maven-version: 3.8.4 - - name: Run java spotless & checkstyle + - name: Run java checkstyle if: steps.filter.outputs.fe_changes == 'true' run: - cd fe && mvn clean spotless:check checkstyle:check + cd fe && mvn clean checkstyle:check + diff --git a/docs/en/community/developer-guide/java-format-code.md b/docs/en/community/developer-guide/java-format-code.md index 43d47515dacf62..bad37cc7f15288 100644 --- a/docs/en/community/developer-guide/java-format-code.md +++ b/docs/en/community/developer-guide/java-format-code.md @@ -1,7 +1,7 @@ --- { - "title": "Java Format Code", - "language": "en" + "title": "Java Format Code", + "language": "en" } --- @@ -89,13 +89,6 @@ After add the `build-support/IntelliJ-code-format.xml` file. Click `Code/Rearran ![](/images/idea-rearrange-code.png) -## Spotless Plugin - -An error was found when checking the project code through `mvn spotless:check`, and then used `mvn spotless:apply` to format the code; when checking again, the formatting error disappeared. - -Tip: We use incremental code formatting, spotless will apply only to files which have changed since `origin/master`. If a `No such reference` error is prompted, please calling `git fetch origin master` before you call Spotless. -Please refer to [how-can-i-enforce-formatting-gradually-aka-ratchet](https://github.com/diffplug/spotless/tree/main/plugin-maven#how-can-i-enforce-formatting-gradually-aka-ratchet) for details. - ## Remove unused header **CTRL + ALT + O --->** to remove the unused imports in windows. @@ -103,3 +96,4 @@ Please refer to [how-can-i-enforce-formatting-gradually-aka-ratchet](https://git Auto remove unused header and reorder according to configure xml: Click `Preferences->Editor->Auto Import->Optimize Imports on the Fly` + diff --git a/docs/zh-CN/community/developer-guide/java-format-code.md b/docs/zh-CN/community/developer-guide/java-format-code.md index 47056f5fa1b2cd..6fad1867ec7729 100644 --- a/docs/zh-CN/community/developer-guide/java-format-code.md +++ b/docs/zh-CN/community/developer-guide/java-format-code.md @@ -1,7 +1,7 @@ --- { - "title": "Java 代码格式化", - "language": "zh-CN" + "title": "Java 代码格式化", + "language": "zh-CN" } --- @@ -42,6 +42,13 @@ standard java package * 禁止使用 `import *` * 禁止使用 `import static` +## 编译时检查 + +现在,在使用`maven`进行编译时,会默认进行`CheckStyle`检查。此检查会略微降低编译速度。如果想跳过此检查,请使用如下命令进行编译 +``` +mvn clean install -DskipTests -Dcheckstyle.skip +``` + ## Checkstyle 插件 现在的 `CI` 之中会有 `formatter-check` 进行代码格式化检测。 @@ -80,17 +87,10 @@ Checkstyle 会按照 [Class and Interface Declarations](https://www.oracle.com/j ![](/images/idea-rearrange-code.png) -## Spotless 插件 - -通过 mvn spotless:check 检查项目代码时发现错误,接着使用 mvn spotless:apply 进行代码格式化;再次检查时,格式化错误消失。 - -提示:我们使用增量代码格式,spotless 仅适用于自“origin/master”以来已更改的文件。如果提示“No such reference”错误,请在调用 Spotless 之前调用“git fetch origin master”。 -请参考 [how-can-i-enforce-formatting-gradually-aka-ratchet](https://github.com/diffplug/spotless/tree/main/plugin-maven#how-can-i-enforce-formatting-gradually-aka-ratchet)。 - ## Remove unused header 默认快捷键 **CTRL + ALT + O --->** 仅仅删除未使用的导入。 自动移除并且 Reorder : -点击 `Preferences->Editor->General->Auto Import->Optimize Imports on the Fly` +点击 `Preferences->Editor->General->Auto Import->Optimize Imports on the Fly` \ No newline at end of file diff --git a/fe/check/spotless/copyright.txt b/fe/check/checkstyle/checkstyle-apache-header.txt similarity index 97% rename from fe/check/spotless/copyright.txt rename to fe/check/checkstyle/checkstyle-apache-header.txt index 5cd17fb5a64e88..6e778edd7530ea 100644 --- a/fe/check/spotless/copyright.txt +++ b/fe/check/checkstyle/checkstyle-apache-header.txt @@ -13,5 +13,4 @@ // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations -// under the License. - +// under the License. \ No newline at end of file diff --git a/fe/check/checkstyle/checkstyle.xml b/fe/check/checkstyle/checkstyle.xml index 34cce78e4f67eb..5c308bcfd8d5c3 100644 --- a/fe/check/checkstyle/checkstyle.xml +++ b/fe/check/checkstyle/checkstyle.xml @@ -7,7 +7,9 @@ regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -42,9 +44,13 @@ under the License. + + + + - + @@ -93,6 +99,14 @@ under the License. + + + + + + + + + diff --git a/fe/check/checkstyle/import-control.xml b/fe/check/checkstyle/import-control.xml index 76bf5a691b4266..16371ce8919206 100644 --- a/fe/check/checkstyle/import-control.xml +++ b/fe/check/checkstyle/import-control.xml @@ -7,7 +7,9 @@ regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -38,4 +40,5 @@ under the License. - \ No newline at end of file + + diff --git a/fe/check/checkstyle/suppressions.xml b/fe/check/checkstyle/suppressions.xml index 06d8dcfb2f6d50..d44bd6d3dbf691 100644 --- a/fe/check/checkstyle/suppressions.xml +++ b/fe/check/checkstyle/suppressions.xml @@ -7,7 +7,9 @@ regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 + Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY @@ -17,8 +19,8 @@ under the License. --> + "-//Checkstyle//DTD SuppressionFilter Configuration 1.2//EN" + "https://checkstyle.org/dtds/suppressions_1_2.dtd"> @@ -61,4 +63,4 @@ under the License. - \ No newline at end of file + diff --git a/fe/pom.xml b/fe/pom.xml index 65948564af3e48..d47dfa681dd9b7 100644 --- a/fe/pom.xml +++ b/fe/pom.xml @@ -17,7 +17,8 @@ KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> - + 4.0.0 org.apache @@ -29,6 +30,157 @@ under the License. ${revision} pom Doris FE Project Parent POM + https://doris.apache.org/ + + + Apache 2.0 License + https://www.apache.org/licenses/LICENSE-2.0.html + repo + + + + scm:git:https://git@github.com/apache/doris.git + scm:git:https://git@github.com/apache/doris.git + scm:git:https://git@github.com/apache/doris.git + HEAD + + + GitHub + https://github.com/apache/doris/issues + + + + Dev Mailing List + dev@doris.apache.org + dev-subscribe@doris.apache.org + dev-unsubscribe@doris.apache.org + + + Commits Mailing List + commits@doris.apache.org + commits-subscribe@doris.apache.org + commits-unsubscribe@doris.apache.org + + + + + + org.codehaus.mojo + flatten-maven-plugin + 1.2.5 + + + org.apache.maven.plugins + maven-dependency-plugin + + + org.commonjava.maven.plugins + directory-maven-plugin + 0.1 + + + directories + + directory-of + + initialize + + fe.dir + + org.apache.doris + fe + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + org.codehaus.mojo + license-maven-plugin + 2.0.0 + + + add-third-party + + add-third-party + + + + + + + + + org.codehaus.mojo + flatten-maven-plugin + 1.2.5 + + true + bom + + + + flatten + process-resources + + flatten + + + + flatten.clean + clean + + clean + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.1.2 + + + com.puppycrawl.tools + checkstyle + 9.3 + + + + check/checkstyle/checkstyle.xml + check/checkstyle/suppressions.xml + UTF-8 + true + true + false + true + + **/apache/doris/thrift/*, + **/apache/parquet/**/* + + + + + validate + validate + + check + + + + + + org.sonarsource.scanner.maven + sonar-maven-plugin + 3.9.1.2184 + + + + fe-common spark-dpp @@ -173,6 +325,46 @@ under the License. shade-format-flatbuffers 1.12.0 + + + general-env + + + !env.CUSTOM_MAVEN_REPO + + + + + central + central maven repo https + https://repo.maven.apache.org/maven2 + + + snapshots + apache snapshots maven repo https + https://repository.apache.org/content/repositories/snapshots/ + + + + + cloudera + https://repository.cloudera.com/artifactory/cloudera-repos/ + + + + + central + https://repo.maven.apache.org/maven2 + + + + + cloudera + https://repository.cloudera.com/artifactory/cloudera-repos/ + + + + @@ -534,12 +726,12 @@ under the License. - org.apache.httpcomponents httpclient + org.apache.httpcomponents - org.apache.httpcomponents httpcore + org.apache.httpcomponents @@ -589,8 +781,8 @@ under the License. io.netty netty - ${netty-3-test.version} test + ${netty-3-test.version} io.netty @@ -674,8 +866,8 @@ under the License. logback-classic - org.elasticsearch.client elasticsearch-rest-high-level-client + org.elasticsearch.client org.apache.hive @@ -900,13 +1092,13 @@ under the License. org.apache.spark spark-sql_2.12 ${spark.version} - provided org.apache.arrow arrow-vector + provided org.apache.spark @@ -921,16 +1113,16 @@ under the License. ${hadoop.version} - javax.servlet servlet-api + javax.servlet io.netty netty - com.fasterxml.jackson.core jackson-databind + com.fasterxml.jackson.core @@ -948,8 +1140,8 @@ under the License. log4j - javax.servlet servlet-api + javax.servlet @@ -1052,16 +1244,16 @@ under the License. ${hudi.version} - commons-httpclient commons-httpclient + commons-httpclient - io.netty netty-all + io.netty - log4j log4j + log4j org.apache.hive @@ -1241,8 +1433,8 @@ under the License. com.clickhouse clickhouse-jdbc ${clickhouse.version} - all provided + all @@ -1372,173 +1564,6 @@ under the License. - - - - - org.codehaus.mojo - flatten-maven-plugin - 1.2.5 - - true - bom - - - - flatten - - flatten - - process-resources - - - flatten.clean - - clean - - clean - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - 3.1.2 - - check/checkstyle/checkstyle.xml - check/checkstyle/suppressions.xml - UTF-8 - true - true - false - true - **/apache/doris/thrift/*, - **/apache/parquet/**/* - - - - com.puppycrawl.tools - checkstyle - 9.3 - - - - - validate - - check - - validate - - - - - org.sonarsource.scanner.maven - sonar-maven-plugin - 3.9.1.2184 - - - com.diffplug.spotless - spotless-maven-plugin - 2.29.0 - - origin/master - - - 1.7 - - - - - ${maven.multiModuleProjectDirectory}/check/spotless/copyright.txt - - - - - org.apache.doris,org.apache,org,,javax,java,\# - - - - - UTF-8 - 4 - true - false - false - true - false - false - custom_1 - false - false - - - Leading blank line - --> - <project - --> - - <project - - - - - - - - - org.codehaus.mojo - flatten-maven-plugin - 1.2.5 - - - org.apache.maven.plugins - maven-dependency-plugin - - - org.commonjava.maven.plugins - directory-maven-plugin - 0.1 - - - directories - - directory-of - - initialize - - fe.dir - - org.apache.doris - fe - - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - org.codehaus.mojo - license-maven-plugin - 2.0.0 - - - add-third-party - - add-third-party - - - - - - com.diffplug.spotless - spotless-maven-plugin - - - @@ -1547,87 +1572,15 @@ under the License. - https://doris.apache.org/ - - - Apache 2.0 License - https://www.apache.org/licenses/LICENSE-2.0.html - repo - - - - - Dev Mailing List - dev-subscribe@doris.apache.org - dev-unsubscribe@doris.apache.org - dev@doris.apache.org - - - Commits Mailing List - commits-subscribe@doris.apache.org - commits-unsubscribe@doris.apache.org - commits@doris.apache.org - - - - scm:git:https://git@github.com/apache/doris.git - scm:git:https://git@github.com/apache/doris.git - scm:git:https://git@github.com/apache/doris.git - HEAD - - - GitHub - https://github.com/apache/doris/issues - - - always - snapshots apache snapshots maven repo https https://repository.apache.org/content/repositories/snapshots/ + + always + - - - general-env - - - !env.CUSTOM_MAVEN_REPO - - - - - central - central maven repo https - https://repo.maven.apache.org/maven2 - - - snapshots - apache snapshots maven repo https - https://repository.apache.org/content/repositories/snapshots/ - - - - - cloudera - https://repository.cloudera.com/artifactory/cloudera-repos/ - - - - - central - https://repo.maven.apache.org/maven2 - - - - - cloudera - https://repository.cloudera.com/artifactory/cloudera-repos/ - - - - From f0bf3fadadc41fe33ac1adb30ca6db0303a49120 Mon Sep 17 00:00:00 2001 From: wangbo Date: Tue, 7 Nov 2023 16:37:54 +0800 Subject: [PATCH 03/88] [test](executor)Add workload group regression test (#26446) --- .../workload_manager_p0/test_curd_wlg.out | 49 ++++ .../workload_manager_p0/test_curd_wlg.groovy | 263 ++++++++++++++++++ 2 files changed, 312 insertions(+) create mode 100644 regression-test/data/workload_manager_p0/test_curd_wlg.out create mode 100644 regression-test/suites/workload_manager_p0/test_curd_wlg.groovy diff --git a/regression-test/data/workload_manager_p0/test_curd_wlg.out b/regression-test/data/workload_manager_p0/test_curd_wlg.out new file mode 100644 index 00000000000000..761d42ab3df680 --- /dev/null +++ b/regression-test/data/workload_manager_p0/test_curd_wlg.out @@ -0,0 +1,49 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !cpu_share -- +2 + +-- !cpu_share_2 -- +2 + +-- !show_1 -- +normal 20 50% true 2147483647 0 0 0% +test_group 10 10% true 2147483647 0 0 0% + +-- !mem_limit_1 -- +2 + +-- !mem_limit_2 -- +normal 20 50% true 2147483647 0 0 0% +test_group 10 11% true 2147483647 0 0 0% + +-- !mem_overcommit_1 -- +2 + +-- !mem_overcommit_2 -- +2 + +-- !mem_overcommit_3 -- +normal 20 50% true 2147483647 0 0 0% +test_group 10 11% false 2147483647 0 0 0% + +-- !cpu_hard_limit_1 -- +2 + +-- !cpu_hard_limit_2 -- +normal 20 50% true 2147483647 0 0 0% +test_group 10 11% false 2147483647 0 0 20% + +-- !queue_1 -- +2 + +-- !show_queue -- +normal 20 50% true 2147483647 0 0 0% +test_group 10 11% false 100 0 0 20% + +-- !select_tvf_1 -- +normal 20 50% true 2147483647 0 0 0% +test_group 10 11% false 100 0 0 20% + +-- !select_tvf_2 -- +test_group 0 1 20% + diff --git a/regression-test/suites/workload_manager_p0/test_curd_wlg.groovy b/regression-test/suites/workload_manager_p0/test_curd_wlg.groovy new file mode 100644 index 00000000000000..c65d9603b776c1 --- /dev/null +++ b/regression-test/suites/workload_manager_p0/test_curd_wlg.groovy @@ -0,0 +1,263 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_crud_wlg") { + def table_name = "wlg_test_table" + + sql "drop table if exists ${table_name}" + + sql """ + CREATE TABLE IF NOT EXISTS `${table_name}` ( + `siteid` int(11) NOT NULL COMMENT "", + `citycode` int(11) NOT NULL COMMENT "", + `userid` int(11) NOT NULL COMMENT "", + `pv` int(11) NOT NULL COMMENT "" + ) ENGINE=OLAP + DUPLICATE KEY(`siteid`) + COMMENT "OLAP" + DISTRIBUTED BY HASH(`siteid`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1", + "in_memory" = "false", + "storage_format" = "V2" + ) + """ + + sql """insert into ${table_name} values + (9,10,11,12), + (1,2,3,4) + """ + + sql "ADMIN SET FRONTEND CONFIG ('enable_workload_group' = 'true');" + + sql "create workload group if not exists normal " + + "properties ( " + + " 'cpu_share'='10', " + + " 'memory_limit'='50%', " + + " 'enable_memory_overcommit'='true' " + + ");" + + // reset normal group property + sql "alter workload group normal properties ( 'cpu_share'='10' );" + sql "alter workload group normal properties ( 'memory_limit'='50%' );" + sql "alter workload group normal properties ( 'enable_memory_overcommit'='true' );" + sql "alter workload group normal properties ( 'max_concurrency'='2147483647' );" + sql "alter workload group normal properties ( 'max_queue_size'='0' );" + sql "alter workload group normal properties ( 'queue_timeout'='0' );" + + sql "set workload_group=normal;" + + // test cpu_share + qt_cpu_share """ select count(1) from ${table_name} """ + + sql "alter workload group normal properties ( 'cpu_share'='20' );" + + qt_cpu_share_2 """ select count(1) from ${table_name} """ + + try { + sql "alter workload group normal properties ( 'cpu_share'='-2' );" + } catch (Exception e) { + assertTrue(e.getMessage().contains("requires a positive integer")); + } + + sql "drop workload group if exists test_group;" + + // test create group + sql "create workload group if not exists test_group " + + "properties ( " + + " 'cpu_share'='10', " + + " 'memory_limit'='10%', " + + " 'enable_memory_overcommit'='true' " + + ");" + sql "set workload_group=test_group;" + + qt_show_1 "select name,cpu_share,memory_limit,enable_memory_overcommit,max_concurrency,max_queue_size,queue_timeout,cpu_hard_limit from workload_groups() order by name;" + + // test memory_limit + try { + sql "alter workload group test_group properties ( 'memory_limit'='100%' );" + } catch (Exception e) { + assertTrue(e.getMessage().contains("cannot be greater than")); + } + sql "alter workload group test_group properties ( 'memory_limit'='11%' );" + qt_mem_limit_1 """ select count(1) from ${table_name} """ + qt_mem_limit_2 "select name,cpu_share,memory_limit,enable_memory_overcommit,max_concurrency,max_queue_size,queue_timeout,cpu_hard_limit from workload_groups() order by name;" + + // test enable_memory_overcommit + try { + sql "alter workload group test_group properties ( 'enable_memory_overcommit'='1' );" + } catch (Exception e) { + assertTrue(e.getMessage().contains("must be true or false")); + } + sql "alter workload group test_group properties ( 'enable_memory_overcommit'='true' );" + qt_mem_overcommit_1 """ select count(1) from ${table_name} """ + sql "alter workload group test_group properties ( 'enable_memory_overcommit'='false' );" + qt_mem_overcommit_2 """ select count(1) from ${table_name} """ + qt_mem_overcommit_3 "select name,cpu_share,memory_limit,enable_memory_overcommit,max_concurrency,max_queue_size,queue_timeout,cpu_hard_limit from workload_groups() order by name;" + + // test cpu_hard_limit + try { + sql "alter workload group test_group properties ( 'cpu_hard_limit'='101%' );" + } catch (Exception e) { + assertTrue(e.getMessage().contains("can not be greater than 100%")); + } + + try { + sql "alter workload group test_group properties ( 'cpu_hard_limit'='99%' );" + } catch (Exception e) { + assertTrue(e.getMessage().contains("can not be greater than 100%")); + } + + sql "alter workload group test_group properties ( 'cpu_hard_limit'='20%' );" + qt_cpu_hard_limit_1 """ select count(1) from ${table_name} """ + qt_cpu_hard_limit_2 "select name,cpu_share,memory_limit,enable_memory_overcommit,max_concurrency,max_queue_size,queue_timeout,cpu_hard_limit from workload_groups() order by name;" + + // test query queue + try { + sql "alter workload group test_group properties ( 'max_concurrency'='-1' );" + } catch (Exception e) { + assertTrue(e.getMessage().contains("requires a positive integer")); + } + + try { + sql "alter workload group test_group properties ( 'max_queue_size'='-1' );" + } catch (Exception e) { + assertTrue(e.getMessage().contains("requires a positive integer")); + } + + try { + sql "alter workload group test_group properties ( 'queue_timeout'='-1' );" + } catch (Exception e) { + assertTrue(e.getMessage().contains("requires a positive integer")); + } + sql "alter workload group test_group properties ( 'max_concurrency'='0' );" + sql "alter workload group test_group properties ( 'max_queue_size'='0' );" + sql "alter workload group test_group properties ( 'queue_timeout'='0' );" + try { + sql "select count(1) from ${table_name}" + } catch (Exception e) { + assertTrue(e.getMessage().contains("queue failed")); + } + + sql "alter workload group test_group properties ( 'max_concurrency'='100' );" + qt_queue_1 """ select count(1) from ${table_name} """ + qt_show_queue "select name,cpu_share,memory_limit,enable_memory_overcommit,max_concurrency,max_queue_size,queue_timeout,cpu_hard_limit from workload_groups() order by name;" + + // test create group failed + // failed for cpu_share + try { + sql "create workload group if not exists test_group2 " + + "properties ( " + + " 'cpu_share'='-1', " + + " 'memory_limit'='1%', " + + " 'enable_memory_overcommit'='true' " + + ");" + } catch (Exception e) { + assertTrue(e.getMessage().contains("requires a positive integer")); + } + // failed for mem_limit + try { + sql "create workload group if not exists test_group2 " + + "properties ( " + + " 'cpu_share'='10', " + + " 'memory_limit'='200%', " + + " 'enable_memory_overcommit'='true' " + + ");" + } catch (Exception e) { + assertTrue(e.getMessage().contains("cannot be greater than")) + } + + try { + sql "create workload group if not exists test_group2 " + + "properties ( " + + " 'cpu_share'='10', " + + " 'memory_limit'='99%', " + + " 'enable_memory_overcommit'='true' " + + ");" + } catch (Exception e) { + assertTrue(e.getMessage().contains("cannot be greater than")) + } + + + // failed for mem_overcommit + try { + sql "create workload group if not exists test_group2 " + + "properties ( " + + " 'cpu_share'='10', " + + " 'memory_limit'='3%', " + + " 'enable_memory_overcommit'='1', " + + " 'cpu_hard_limit'='1%' " + + ");" + } catch (Exception e) { + assertTrue(e.getMessage().contains("must be true or false")); + } + + // failed for cpu_hard_limit + try { + sql "create workload group if not exists test_group2 " + + "properties ( " + + " 'cpu_share'='10', " + + " 'memory_limit'='3%', " + + " 'enable_memory_overcommit'='true', " + + " 'cpu_hard_limit'='120%' " + + ");" + } catch (Exception e) { + assertTrue(e.getMessage().contains("can not be greater than")); + } + + try { + sql "create workload group if not exists test_group2 " + + "properties ( " + + " 'cpu_share'='10', " + + " 'memory_limit'='3%', " + + " 'enable_memory_overcommit'='true', " + + " 'cpu_hard_limit'='99%' " + + ");" + } catch (Exception e) { + assertTrue(e.getMessage().contains("can not be greater than")); + } + + // test show workload groups + qt_select_tvf_1 "select name,cpu_share,memory_limit,enable_memory_overcommit,max_concurrency,max_queue_size,queue_timeout,cpu_hard_limit from workload_groups() order by name;" + + qt_select_tvf_2 "select name, waiting_query_num,running_query_num,cpu_hard_limit from workload_groups() where name='test_group' order by name;" + + // test auth + sql """drop user if exists test_wlg_user""" + sql "CREATE USER 'test_wlg_user'@'%' IDENTIFIED BY '12345';" + sql """grant SELECT_PRIV on *.*.* to test_wlg_user;""" + connect(user = 'test_wlg_user', password = '12345', url = context.config.jdbcUrl) { + sql """ select 1; """ + } + + connect(user = 'test_wlg_user', password = '12345', url = context.config.jdbcUrl) { + sql """ set workload_group = test_group; """ + try { + sql """ select 1; """ + } catch (Exception e) { + e.getMessage().contains("Access denied") + } + } + + sql "GRANT USAGE_PRIV ON WORKLOAD GROUP 'test_group' TO 'test_wlg_user'@'%';" + + connect(user = 'test_wlg_user', password = '12345', url = context.config.jdbcUrl) { + sql """ set workload_group = test_group; """ + sql """ select 1; """ + } + +} From 3ad8e27b09e1d71726c4e0400d3c47187e3b3694 Mon Sep 17 00:00:00 2001 From: bobhan1 Date: Tue, 7 Nov 2023 16:51:38 +0800 Subject: [PATCH 04/88] [Fix](autoinc) Init auto increment info in VOlapTableSinkV2 (#26502) --- be/src/vec/sink/vtablet_sink_v2.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/be/src/vec/sink/vtablet_sink_v2.cpp b/be/src/vec/sink/vtablet_sink_v2.cpp index f38785f53f469a..eba1d08acc0d20 100644 --- a/be/src/vec/sink/vtablet_sink_v2.cpp +++ b/be/src/vec/sink/vtablet_sink_v2.cpp @@ -131,7 +131,8 @@ Status VOlapTableSinkV2::prepare(RuntimeState* state) { _tuple_desc_id); } _block_convertor = std::make_unique(_output_tuple_desc); - + _block_convertor->init_autoinc_info(_schema->db_id(), _schema->table_id(), + _state->batch_size()); // add all counter _input_rows_counter = ADD_COUNTER(_profile, "RowsRead", TUnit::UNIT); _output_rows_counter = ADD_COUNTER(_profile, "RowsReturned", TUnit::UNIT); From b0788652bd568365693992b416032c75e61c877e Mon Sep 17 00:00:00 2001 From: Guangdong Liu Date: Tue, 7 Nov 2023 17:16:07 +0800 Subject: [PATCH 05/88] [bugfix](clickhouse) fix datetime convert error. (#26128) --- .../jdbc/client/JdbcClickHouseClient.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java index 292dea760efd15..b68ec481d3d2ec 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcClickHouseClient.java @@ -58,25 +58,26 @@ protected Type jdbcTypeToDoris(JdbcFieldSchema fieldSchema) { return createDecimalOrStringType(precision, scale); } - if ("String".contains(ckType) || ckType.startsWith("Enum") - || ckType.startsWith("IPv") || "UUID".contains(ckType) + if ("String".contains(ckType) + || ckType.startsWith("Enum") + || ckType.startsWith("IPv") + || "UUID".contains(ckType) || ckType.startsWith("FixedString")) { return ScalarType.createStringType(); } if (ckType.startsWith("DateTime")) { // DateTime with second precision - if (ckType.equals("DateTime")) { + if (ckType.startsWith("DateTime(") || ckType.equals("DateTime")) { return ScalarType.createDatetimeV2Type(0); } else { - // DateTime64 with [0~9] precision int indexStart = ckType.indexOf('('); int indexEnd = ckType.indexOf(')'); if (indexStart != -1 && indexEnd != -1) { String scaleStr = ckType.substring(indexStart + 1, indexEnd); int scale = Integer.parseInt(scaleStr); - if (scale > 6) { - scale = 6; + if (scale > JDBC_DATETIME_SCALE) { + scale = JDBC_DATETIME_SCALE; } // return with the actual scale return ScalarType.createDatetimeV2Type(scale); From ef95e962c7e4622caed3550800231e18c9c6ed6c Mon Sep 17 00:00:00 2001 From: Mryange <59914473+Mryange@users.noreply.github.com> Date: Tue, 7 Nov 2023 17:25:20 +0800 Subject: [PATCH 06/88] [fix](timev2) fix Type not implemented in fold by be (#26478) --- be/src/runtime/fold_constant_executor.cpp | 5 +++ .../data/correctness/test_timev2_fold.out | 13 +++++++ .../correctness/test_timev2_fold.groovy | 35 +++++++++++++++++++ 3 files changed, 53 insertions(+) create mode 100644 regression-test/data/correctness/test_timev2_fold.out create mode 100644 regression-test/suites/correctness/test_timev2_fold.groovy diff --git a/be/src/runtime/fold_constant_executor.cpp b/be/src/runtime/fold_constant_executor.cpp index e5fd16418d6ff7..c3dd21406ef535 100644 --- a/be/src/runtime/fold_constant_executor.cpp +++ b/be/src/runtime/fold_constant_executor.cpp @@ -195,6 +195,11 @@ string FoldConstantExecutor::_get_result(void* src, size_t size, const TypeDescr double val = *reinterpret_cast(src); return fmt::format("{}", val); } + case TYPE_TIMEV2: { + constexpr static auto ratio_to_time = (1000 * 1000); + double val = *reinterpret_cast(src); + return fmt::format("{}", val / ratio_to_time); + } case TYPE_CHAR: case TYPE_VARCHAR: case TYPE_STRING: diff --git a/regression-test/data/correctness/test_timev2_fold.out b/regression-test/data/correctness/test_timev2_fold.out new file mode 100644 index 00000000000000..b070f10507f597 --- /dev/null +++ b/regression-test/data/correctness/test_timev2_fold.out @@ -0,0 +1,13 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select1 -- +-07:00:00 + +-- !select2 -- +-07:00:00 + +-- !select3 -- +-07:00:00 + +-- !select4 -- +-07:00:00 + diff --git a/regression-test/suites/correctness/test_timev2_fold.groovy b/regression-test/suites/correctness/test_timev2_fold.groovy new file mode 100644 index 00000000000000..8ce0576516233b --- /dev/null +++ b/regression-test/suites/correctness/test_timev2_fold.groovy @@ -0,0 +1,35 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_timev2_fold") { + sql """ set enable_nereids_planner=false,enable_fold_constant_by_be=false """ + qt_select1 """ + select timediff( convert_tz("2020-05-05 00:00:00", 'UTC', 'America/Los_Angeles'), "2020-05-05 00:00:00"); + """ + sql """ set enable_nereids_planner=true,enable_fold_constant_by_be=false """ + qt_select2 """ + select timediff( convert_tz("2020-05-05 00:00:00", 'UTC', 'America/Los_Angeles'), "2020-05-05 00:00:00"); + """ + sql """ set enable_nereids_planner=false,enable_fold_constant_by_be=true """ + qt_select3 """ + select timediff( convert_tz("2020-05-05 00:00:00", 'UTC', 'America/Los_Angeles'), "2020-05-05 00:00:00"); + """ + sql """ set enable_nereids_planner=true,enable_fold_constant_by_be=true """ + qt_select4 """ + select timediff( convert_tz("2020-05-05 00:00:00", 'UTC', 'America/Los_Angeles'), "2020-05-05 00:00:00"); + """ +} \ No newline at end of file From a404ff5ab990ed7aac7fdb607d09f4ea4ab54227 Mon Sep 17 00:00:00 2001 From: meiyi Date: Tue, 7 Nov 2023 18:17:45 +0800 Subject: [PATCH 07/88] [fix](regression) fix group commit regression test (#26519) --- be/src/runtime/stream_load/new_load_stream_mgr.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/be/src/runtime/stream_load/new_load_stream_mgr.h b/be/src/runtime/stream_load/new_load_stream_mgr.h index 9c3385443659d9..45be8bb306935e 100644 --- a/be/src/runtime/stream_load/new_load_stream_mgr.h +++ b/be/src/runtime/stream_load/new_load_stream_mgr.h @@ -45,12 +45,14 @@ class NewLoadStreamMgr { { std::lock_guard l(_lock); if (auto iter = _stream_map.find(id); iter != _stream_map.end()) { - return Status::InternalError("id already exist"); + std::stringstream ss; + ss << "id: " << id << " already exist"; + return Status::InternalError(ss.str()); } _stream_map.emplace(id, stream); } - VLOG_NOTICE << "put stream load pipe: " << id; + LOG(INFO) << "put stream load pipe: " << id; return Status::OK(); } @@ -61,6 +63,7 @@ class NewLoadStreamMgr { return iter->second; } } + LOG(INFO) << "stream load pipe does not exist: " << id; return nullptr; } @@ -68,7 +71,7 @@ class NewLoadStreamMgr { std::lock_guard l(_lock); if (auto iter = _stream_map.find(id); iter != _stream_map.end()) { _stream_map.erase(iter); - VLOG_NOTICE << "remove stream load pipe: " << id; + LOG(INFO) << "remove stream load pipe: " << id; } } From 2feed57f47a78564786ab0110ccd2a617a266331 Mon Sep 17 00:00:00 2001 From: Qi Chen Date: Tue, 7 Nov 2023 18:43:30 +0800 Subject: [PATCH 08/88] [Fix](fs_benchmark_tools) Fix `run_fs_benchmark.sh` classpath issue. (#26183) Fix run_fs_benchmark.sh classpath issue. --- bin/run-fs-benchmark.sh | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/bin/run-fs-benchmark.sh b/bin/run-fs-benchmark.sh index 8eb0781106a0de..e446d2fb4ed95d 100755 --- a/bin/run-fs-benchmark.sh +++ b/bin/run-fs-benchmark.sh @@ -47,12 +47,17 @@ if [[ "${MAX_FILE_COUNT}" -lt 65536 ]]; then fi # add java libs -for f in "${DORIS_HOME}/lib/java_extensions"/*.jar; do - if [[ -z "${DORIS_CLASSPATH}" ]]; then - export DORIS_CLASSPATH="${f}" - else - export DORIS_CLASSPATH="${f}:${DORIS_CLASSPATH}" - fi +preload_jars=("preload-extensions") +preload_jars+=("java-udf") + +for preload_jar_dir in "${preload_jars[@]}"; do + for f in "${DORIS_HOME}/lib/java_extensions/${preload_jar_dir}"/*.jar; do + if [[ -z "${DORIS_CLASSPATH}" ]]; then + export DORIS_CLASSPATH="${f}" + else + export DORIS_CLASSPATH="${DORIS_CLASSPATH}:${f}" + fi + done done if [[ -d "${DORIS_HOME}/lib/hadoop_hdfs/" ]]; then @@ -71,6 +76,13 @@ if [[ -d "${DORIS_HOME}/lib/hadoop_hdfs/" ]]; then done fi +# add custome_libs to CLASSPATH +if [[ -d "${DORIS_HOME}/custom_lib" ]]; then + for f in "${DORIS_HOME}/custom_lib"/*.jar; do + DORIS_CLASSPATH="${DORIS_CLASSPATH}:${f}" + done +fi + if [[ -n "${HADOOP_CONF_DIR}" ]]; then export DORIS_CLASSPATH="${DORIS_CLASSPATH}:${HADOOP_CONF_DIR}" fi From 38a14c3325e3796cff9f2dc26aa4dc4e139c5243 Mon Sep 17 00:00:00 2001 From: Liqf <109049295+LemonLiTree@users.noreply.github.com> Date: Tue, 7 Nov 2023 19:01:27 +0800 Subject: [PATCH 09/88] [docs](fix) add bitmap_remove in sidebars.json (#26523) --- docs/sidebars.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/sidebars.json b/docs/sidebars.json index c3e73573c083a4..9fd9cf97554d56 100644 --- a/docs/sidebars.json +++ b/docs/sidebars.json @@ -608,7 +608,8 @@ "sql-manual/sql-functions/bitmap-functions/orthogonal-bitmap-intersect-count", "sql-manual/sql-functions/bitmap-functions/orthogonal-bitmap-expr-calculate", "sql-manual/sql-functions/bitmap-functions/orthogonal-bitmap-expr-calculate-count", - "sql-manual/sql-functions/bitmap-functions/bitmap-hash64" + "sql-manual/sql-functions/bitmap-functions/bitmap-hash64", + "sql-manual/sql-functions/bitmap-functions/bitmap-remove" ] }, { From ad1f6350701516c82509da0612574567989bd7b6 Mon Sep 17 00:00:00 2001 From: zhiqiang Date: Tue, 7 Nov 2023 05:14:57 -0600 Subject: [PATCH 10/88] [Feature](auditloader) Plugin auditloader use auth token to avoid using cleartext passwords in config (#26278) Doris FE will check if stream load http request has auth token after checking password failed; Plugin audit-log loader can use auth token if plugin config set use_auth_token to true Co-authored-by: Mingyu Chen --- .../apache/doris/httpv2/rest/LoadAction.java | 112 +++++++++++++++++- .../auditloader/src/main/assembly/plugin.conf | 3 + .../doris/plugin/audit/AuditLoaderPlugin.java | 20 +++- .../doris/plugin/audit/DorisStreamLoader.java | 11 +- 4 files changed, 138 insertions(+), 8 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java index 9c5902d748a4d6..ff6e98a6c780e3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/httpv2/rest/LoadAction.java @@ -24,6 +24,7 @@ import org.apache.doris.common.LoadException; import org.apache.doris.httpv2.entity.ResponseEntityBuilder; import org.apache.doris.httpv2.entity.RestBaseResult; +import org.apache.doris.httpv2.exception.UnauthorizedException; import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.qe.ConnectContext; import org.apache.doris.service.ExecuteEnv; @@ -43,6 +44,7 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.view.RedirectView; +import java.net.URI; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -81,7 +83,20 @@ public Object streamLoad(HttpServletRequest request, return redirectToHttps(request); } - executeCheckPassword(request, response); + try { + executeCheckPassword(request, response); + } catch (UnauthorizedException unauthorizedException) { + if (LOG.isDebugEnabled()) { + LOG.debug("Check password failed, going to check auth token, request: {}", request.toString()); + } + + if (!checkClusterToken(request)) { + throw unauthorizedException; + } else { + return executeWithClusterToken(request, db, table, true); + } + } + return executeWithoutPassword(request, response, db, table, true); } @@ -257,4 +272,99 @@ private TNetworkAddress selectRedirectBackend(String clusterName) throws LoadExc } return new TNetworkAddress(backend.getHost(), backend.getHttpPort()); } + + // NOTE: This function can only be used for AuditlogPlugin stream load for now. + // AuditlogPlugin should be re-disigned carefully, and blow method focuses on + // temporarily addressing the users' needs for audit logs. + // So this function is not widely tested under general scenario + private boolean checkClusterToken(HttpServletRequest request) { + if (LOG.isDebugEnabled()) { + LOG.debug("Checking cluser token, request {}", request.toString()); + } + + String authToken = request.getHeader("token"); + + if (Strings.isNullOrEmpty(authToken)) { + return false; + } + + return Env.getCurrentEnv().getLoadManager().getTokenManager().checkAuthToken(authToken); + } + + // NOTE: This function can only be used for AuditlogPlugin stream load for now. + // AuditlogPlugin should be re-disigned carefully, and blow method focuses on + // temporarily addressing the users' needs for audit logs. + // So this function is not widely tested under general scenario + private Object executeWithClusterToken(HttpServletRequest request, String db, + String table, boolean isStreamLoad) { + try { + ConnectContext ctx = new ConnectContext(); + ctx.setEnv(Env.getCurrentEnv()); + ctx.setThreadLocalInfo(); + ctx.setCluster(SystemInfoService.DEFAULT_CLUSTER); + ctx.setRemoteIP(request.getRemoteAddr()); + + String dbName = db; + String tableName = table; + // A 'Load' request must have 100-continue header + if (request.getHeader(HttpHeaderNames.EXPECT.toString()) == null) { + return new RestBaseResult("There is no 100-continue header"); + } + + final String clusterName = ConnectContext.get().getClusterName(); + if (Strings.isNullOrEmpty(clusterName)) { + return new RestBaseResult("No cluster selected."); + } + + if (Strings.isNullOrEmpty(dbName)) { + return new RestBaseResult("No database selected."); + } + + if (Strings.isNullOrEmpty(tableName)) { + return new RestBaseResult("No table selected."); + } + + String label = request.getParameter(LABEL_KEY); + if (isStreamLoad) { + label = request.getHeader(LABEL_KEY); + } + + if (!isStreamLoad && Strings.isNullOrEmpty(label)) { + // for stream load, the label can be generated by system automatically + return new RestBaseResult("No label selected."); + } + + TNetworkAddress redirectAddr = selectRedirectBackend(clusterName); + + LOG.info("Redirect load action with auth token to destination={}," + + "stream: {}, db: {}, tbl: {}, label: {}", + redirectAddr.toString(), isStreamLoad, dbName, tableName, label); + + URI urlObj = null; + URI resultUriObj = null; + String urlStr = request.getRequestURI(); + String userInfo = null; + + try { + urlObj = new URI(urlStr); + resultUriObj = new URI("http", userInfo, redirectAddr.getHostname(), + redirectAddr.getPort(), urlObj.getPath(), "", null); + } catch (Exception e) { + throw new RuntimeException(e); + } + String redirectUrl = resultUriObj.toASCIIString(); + if (!Strings.isNullOrEmpty(request.getQueryString())) { + redirectUrl += request.getQueryString(); + } + LOG.info("Redirect url: {}", redirectUrl); + RedirectView redirectView = new RedirectView(redirectUrl); + redirectView.setContentType("text/html;charset=utf-8"); + redirectView.setStatusCode(org.springframework.http.HttpStatus.TEMPORARY_REDIRECT); + + return redirectView; + } catch (Exception e) { + LOG.warn("Failed to execute stream load with cluster token, {}", e); + return new RestBaseResult(e.getMessage()); + } + } } diff --git a/fe_plugins/auditloader/src/main/assembly/plugin.conf b/fe_plugins/auditloader/src/main/assembly/plugin.conf index 31f7bd3f35616f..aec8724fd9612c 100755 --- a/fe_plugins/auditloader/src/main/assembly/plugin.conf +++ b/fe_plugins/auditloader/src/main/assembly/plugin.conf @@ -51,3 +51,6 @@ user=root # Doris user's password password= +# Use doris cluster token for stream load authorization, if true, user and password will be ignored. +use_auth_token=false + diff --git a/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java b/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java index 2aa1246dd6b56b..3cfb0eeeaee3a5 100755 --- a/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java +++ b/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java @@ -18,6 +18,7 @@ package org.apache.doris.plugin.audit; import org.apache.doris.common.Config; +import org.apache.doris.catalog.Env; import org.apache.doris.plugin.AuditEvent; import org.apache.doris.plugin.AuditPlugin; import org.apache.doris.plugin.Plugin; @@ -84,7 +85,6 @@ public void init(PluginInfo info, PluginContext ctx) throws PluginException { this.lastLoadTimeSlowLog = System.currentTimeMillis(); loadConfig(ctx, info.getProperties()); - this.auditEventQueue = Queues.newLinkedBlockingDeque(conf.maxQueueSize); this.streamLoader = new DorisStreamLoader(conf); this.loadThread = new Thread(new LoadWorker(this.streamLoader), "audit loader thread"); @@ -209,7 +209,16 @@ private void loadIfNecessary(DorisStreamLoader loader, boolean slowLog) { if (logBuffer.length() >= conf.maxBatchSize || currentTime - lastLoadTime >= conf.maxBatchIntervalSec * 1000) { // begin to load try { - DorisStreamLoader.LoadResponse response = loader.loadBatch(logBuffer, slowLog); + String token = ""; + if (conf.use_auth_token) { + try { + // Acquire token from master + token = Env.getCurrentEnv().getLoadManager().getTokenManager().acquireToken(); + } catch (Exception e) { + LOG.error("Failed to get auth token: {}", e); + } + } + DorisStreamLoader.LoadResponse response = loader.loadBatch(logBuffer, slowLog, token); LOG.debug("audit loader response: {}", response); } catch (Exception e) { LOG.debug("encounter exception when putting current audit batch, discard current batch", e); @@ -248,6 +257,7 @@ public static class AuditLoaderConf { public static final String PROP_ENABLE_SLOW_LOG = "enable_slow_log"; // the max stmt length to be loaded in audit table. public static final String MAX_STMT_LENGTH = "max_stmt_length"; + public static final String USE_AUTH_TOKEN = "use_auth_token"; public long maxBatchSize = 50 * 1024 * 1024; public long maxBatchIntervalSec = 60; @@ -262,6 +272,9 @@ public static class AuditLoaderConf { // the identity of FE which run this plugin public String feIdentity = ""; public int max_stmt_length = 4096; + // auth_token is not used by default + public boolean use_auth_token = false; + public void init(Map properties) throws PluginException { try { @@ -302,6 +315,9 @@ public void init(Map properties) throws PluginException { if (properties.containsKey(MAX_STMT_LENGTH)) { max_stmt_length = Integer.parseInt(properties.get(MAX_STMT_LENGTH)); } + if (properties.containsKey(USE_AUTH_TOKEN)) { + use_auth_token = Boolean.valueOf(properties.get(USE_AUTH_TOKEN)); + } } catch (Exception e) { throw new PluginException(e.getMessage()); } diff --git a/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/DorisStreamLoader.java b/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/DorisStreamLoader.java index 2781bcc20734a0..d389f0dfa8156c 100644 --- a/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/DorisStreamLoader.java +++ b/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/DorisStreamLoader.java @@ -59,11 +59,12 @@ public DorisStreamLoader(AuditLoaderPlugin.AuditLoaderConf conf) { this.feIdentity = conf.feIdentity.replaceAll("\\.", "_"); } - private HttpURLConnection getConnection(String urlStr, String label) throws IOException { + private HttpURLConnection getConnection(String urlStr, String label, String clusterToken) throws IOException { URL url = new URL(urlStr); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setInstanceFollowRedirects(false); conn.setRequestMethod("PUT"); + conn.setRequestProperty("token", clusterToken); conn.setRequestProperty("Authorization", "Basic " + authEncoding); conn.addRequestProperty("Expect", "100-continue"); conn.addRequestProperty("Content-Type", "text/plain; charset=UTF-8"); @@ -114,7 +115,7 @@ private String getContent(HttpURLConnection conn) { return response.toString(); } - public LoadResponse loadBatch(StringBuilder sb, boolean slowLog) { + public LoadResponse loadBatch(StringBuilder sb, boolean slowLog, String clusterToken) { Calendar calendar = Calendar.getInstance(); String label = String.format("_log_%s%02d%02d_%02d%02d%02d_%s", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH) + 1, calendar.get(Calendar.DAY_OF_MONTH), @@ -127,10 +128,10 @@ public LoadResponse loadBatch(StringBuilder sb, boolean slowLog) { // build request and send to fe if (slowLog) { label = "slow" + label; - feConn = getConnection(slowLogLoadUrlStr, label); + feConn = getConnection(slowLogLoadUrlStr, label, clusterToken); } else { label = "audit" + label; - feConn = getConnection(auditLogLoadUrlStr, label); + feConn = getConnection(auditLogLoadUrlStr, label, clusterToken); } int status = feConn.getResponseCode(); // fe send back http response code TEMPORARY_REDIRECT 307 and new be location @@ -143,7 +144,7 @@ public LoadResponse loadBatch(StringBuilder sb, boolean slowLog) { throw new Exception("redirect location is null"); } // build request and send to new be location - beConn = getConnection(location, label); + beConn = getConnection(location, label, clusterToken); // send data to be try (BufferedOutputStream bos = new BufferedOutputStream(beConn.getOutputStream())) { bos.write(sb.toString().getBytes()); From d6eb3324a1454663b6d41701ff22ab683b5056f5 Mon Sep 17 00:00:00 2001 From: Kaijie Chen Date: Tue, 7 Nov 2023 19:35:12 +0800 Subject: [PATCH 11/88] [cleanup](load) remove unused code in sink v2 header (#26521) --- be/src/vec/sink/vtablet_sink_v2.h | 27 --------------------------- 1 file changed, 27 deletions(-) diff --git a/be/src/vec/sink/vtablet_sink_v2.h b/be/src/vec/sink/vtablet_sink_v2.h index 42103fa03b1079..63f0985eb090ce 100644 --- a/be/src/vec/sink/vtablet_sink_v2.h +++ b/be/src/vec/sink/vtablet_sink_v2.h @@ -84,24 +84,6 @@ class VOlapTableSinkV2; class DeltaWriterV2Map; using Streams = std::vector>; -using NodeIdForStream = std::unordered_map; -using NodePartitionTabletMapping = - std::unordered_map>>; - -class StreamSinkHandler : public brpc::StreamInputHandler { -public: - StreamSinkHandler(VOlapTableSinkV2* sink) : _sink(sink) {} - - int on_received_messages(brpc::StreamId id, butil::IOBuf* const messages[], - size_t size) override; - - void on_idle_timeout(brpc::StreamId id) override {} - - void on_closed(brpc::StreamId id) override; - -private: - VOlapTableSinkV2* _sink; -}; struct Rows { int64_t partition_id; @@ -222,15 +204,6 @@ class VOlapTableSinkV2 final : public DataSink { std::unordered_map> _streams_for_node; size_t _stream_index = 0; std::shared_ptr _delta_writer_for_tablet; - - std::atomic _pending_streams {0}; - - std::unordered_map> _tablet_success_map; - std::unordered_map> _tablet_failure_map; - bthread::Mutex _tablet_success_map_mutex; - bthread::Mutex _tablet_failure_map_mutex; - - friend class StreamSinkHandler; }; } // namespace vectorized From 2bb3ef198144954583aea106591959ee09932cba Mon Sep 17 00:00:00 2001 From: Jerry Hu Date: Tue, 7 Nov 2023 19:37:31 +0800 Subject: [PATCH 12/88] [refactor](scan) delete bloom_filter_predicate (#26499) --- be/src/exprs/create_predicate_function.h | 12 +- be/src/olap/bloom_filter_predicate.h | 197 ------------------ be/src/olap/olap_common.h | 1 + be/src/olap/predicate_creator.h | 1 - be/src/olap/reader.cpp | 16 -- be/src/olap/reader.h | 3 - .../rowset/segment_v2/segment_iterator.cpp | 3 +- be/src/pipeline/exec/olap_scan_operator.cpp | 2 + be/src/pipeline/exec/olap_scan_operator.h | 1 + be/src/pipeline/exec/scan_operator.cpp | 20 -- be/src/pipeline/exec/scan_operator.h | 3 - be/src/vec/exec/scan/new_olap_scan_node.cpp | 2 + be/src/vec/exec/scan/new_olap_scan_node.h | 1 + be/src/vec/exec/scan/new_olap_scanner.cpp | 1 + be/src/vec/exec/scan/vscan_node.cpp | 17 -- be/src/vec/exec/scan/vscan_node.h | 3 - 16 files changed, 11 insertions(+), 272 deletions(-) delete mode 100644 be/src/olap/bloom_filter_predicate.h diff --git a/be/src/exprs/create_predicate_function.h b/be/src/exprs/create_predicate_function.h index 0e792563acf14a..f4e0601459ea62 100644 --- a/be/src/exprs/create_predicate_function.h +++ b/be/src/exprs/create_predicate_function.h @@ -17,11 +17,11 @@ #pragma once +#include "bloom_filter_func.h" #include "exprs/hybrid_set.h" #include "exprs/minmax_predicate.h" #include "function_filter.h" #include "olap/bitmap_filter_predicate.h" -#include "olap/bloom_filter_predicate.h" #include "olap/column_predicate.h" #include "olap/in_list_predicate.h" #include "olap/like_column_predicate.h" @@ -225,16 +225,6 @@ inline auto create_bitmap_filter(PrimitiveType type) { return create_bitmap_predicate_function(type); } -template -ColumnPredicate* create_olap_column_predicate(uint32_t column_id, - const std::shared_ptr& filter, - int be_exec_version, const TabletColumn*) { - std::shared_ptr filter_olap; - filter_olap.reset(create_bloom_filter(PT)); - filter_olap->light_copy(filter.get()); - return new BloomFilterColumnPredicate(column_id, filter, be_exec_version); -} - template ColumnPredicate* create_olap_column_predicate(uint32_t column_id, const std::shared_ptr& filter, diff --git a/be/src/olap/bloom_filter_predicate.h b/be/src/olap/bloom_filter_predicate.h deleted file mode 100644 index d2816be9966dc3..00000000000000 --- a/be/src/olap/bloom_filter_predicate.h +++ /dev/null @@ -1,197 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#pragma once - -#include "exprs/bloom_filter_func.h" -#include "exprs/runtime_filter.h" -#include "olap/column_predicate.h" -#include "runtime/primitive_type.h" -#include "vec/columns/column_dictionary.h" -#include "vec/columns/column_nullable.h" -#include "vec/columns/column_vector.h" -#include "vec/columns/predicate_column.h" -#include "vec/exprs/vruntimefilter_wrapper.h" - -namespace doris { - -// only use in runtime filter and segment v2 - -template -class BloomFilterColumnPredicate : public ColumnPredicate { -public: - using SpecificFilter = BloomFilterFunc; - - BloomFilterColumnPredicate(uint32_t column_id, - const std::shared_ptr& filter, - int be_exec_version) - : ColumnPredicate(column_id), - _filter(filter), - _specific_filter(reinterpret_cast(_filter.get())), - _be_exec_version(be_exec_version) {} - ~BloomFilterColumnPredicate() override = default; - - PredicateType type() const override { return PredicateType::BF; } - - Status evaluate(BitmapIndexIterator* iterators, uint32_t num_rows, - roaring::Roaring* roaring) const override { - return Status::OK(); - } - - uint16_t evaluate(const vectorized::IColumn& column, uint16_t* sel, - uint16_t size) const override; - -private: - template - uint16_t evaluate(const vectorized::IColumn& column, const uint8_t* null_map, uint16_t* sel, - uint16_t size) const { - if constexpr (is_nullable) { - DCHECK(null_map); - } - - uint24_t tmp_uint24_value; - auto get_cell_value = [&tmp_uint24_value](auto& data) { - if constexpr (std::is_same_v, uint32_t> && - T == PrimitiveType::TYPE_DATE) { - memcpy((char*)(&tmp_uint24_value), (char*)(&data), sizeof(uint24_t)); - return (const char*)&tmp_uint24_value; - } else { - return (const char*)&data; - } - }; - - uint16_t new_size = 0; - if (column.is_column_dictionary()) { - auto* dict_col = reinterpret_cast(&column); - if (_be_exec_version >= 2) { - for (uint16_t i = 0; i < size; i++) { - uint16_t idx = sel[i]; - sel[new_size] = idx; - if constexpr (is_nullable) { - new_size += !null_map[idx] && _specific_filter->find_uint32_t( - dict_col->get_crc32_hash_value(idx)); - } else { - new_size += _specific_filter->find_uint32_t( - dict_col->get_crc32_hash_value(idx)); - } - } - } else { - for (uint16_t i = 0; i < size; i++) { - uint16_t idx = sel[i]; - sel[new_size] = idx; - if constexpr (is_nullable) { - new_size += !null_map[idx] && - _specific_filter->find_uint32_t(dict_col->get_hash_value(idx)); - } else { - new_size += _specific_filter->find_uint32_t(dict_col->get_hash_value(idx)); - } - } - } - } else if (is_string_type(T) && _be_exec_version >= 2) { - auto& pred_col = - reinterpret_cast< - const vectorized::PredicateColumnType>*>( - &column) - ->get_data(); - - auto pred_col_data = pred_col.data(); - const bool is_dense_column = pred_col.size() == size; - for (uint16_t i = 0; i < size; i++) { - uint16_t idx = is_dense_column ? i : sel[i]; - if constexpr (is_nullable) { - if (!null_map[idx] && - _specific_filter->find_crc32_hash(get_cell_value(pred_col_data[idx]))) { - sel[new_size++] = idx; - } - } else { - if (_specific_filter->find_crc32_hash(get_cell_value(pred_col_data[idx]))) { - sel[new_size++] = idx; - } - } - } - } else if (IRuntimeFilter::enable_use_batch(_be_exec_version > 0, T)) { - const auto& data = - reinterpret_cast< - const vectorized::PredicateColumnType>*>( - &column) - ->get_data(); - new_size = _specific_filter->find_fixed_len_olap_engine((char*)data.data(), null_map, - sel, size, data.size() != size); - } else { - auto& pred_col = - reinterpret_cast< - const vectorized::PredicateColumnType>*>( - &column) - ->get_data(); - - auto pred_col_data = pred_col.data(); -#define EVALUATE_WITH_NULL_IMPL(IDX) \ - !null_map[IDX] && _specific_filter->find_olap_engine(get_cell_value(pred_col_data[IDX])) -#define EVALUATE_WITHOUT_NULL_IMPL(IDX) \ - _specific_filter->find_olap_engine(get_cell_value(pred_col_data[IDX])) - EVALUATE_BY_SELECTOR(EVALUATE_WITH_NULL_IMPL, EVALUATE_WITHOUT_NULL_IMPL) -#undef EVALUATE_WITH_NULL_IMPL -#undef EVALUATE_WITHOUT_NULL_IMPL - } - return new_size; - } - - std::string _debug_string() const override { - std::string info = "BloomFilterColumnPredicate(" + type_to_string(T) + ")"; - return info; - } - - int get_filter_id() const override { - int filter_id = _filter->get_filter_id(); - DCHECK(filter_id != -1); - return filter_id; - } - bool is_filter() const override { return true; } - - std::shared_ptr _filter; - SpecificFilter* _specific_filter; // owned by _filter - mutable bool _always_true = false; - mutable bool _has_calculate_filter = false; - int _be_exec_version; -}; - -template -uint16_t BloomFilterColumnPredicate::evaluate(const vectorized::IColumn& column, uint16_t* sel, - uint16_t size) const { - uint16_t new_size = 0; - if (_always_true) { - return size; - } - if (column.is_nullable()) { - auto* nullable_col = reinterpret_cast(&column); - auto& null_map_data = nullable_col->get_null_map_column().get_data(); - new_size = - evaluate(nullable_col->get_nested_column(), null_map_data.data(), sel, size); - } else { - new_size = evaluate(column, nullptr, sel, size); - } - // If the pass rate is very high, for example > 50%, then the bloomfilter is useless. - // Some bloomfilter is useless, for example ssb 4.3, it consumes a lot of cpu but it is - // useless. - _evaluated_rows += size; - _passed_rows += new_size; - vectorized::VRuntimeFilterWrapper::calculate_filter( - _evaluated_rows - _passed_rows, _evaluated_rows, _has_calculate_filter, _always_true); - return new_size; -} - -} //namespace doris diff --git a/be/src/olap/olap_common.h b/be/src/olap/olap_common.h index 07a6d2964814de..78ff8dd82f180f 100644 --- a/be/src/olap/olap_common.h +++ b/be/src/olap/olap_common.h @@ -312,6 +312,7 @@ struct OlapReaderStatistics { int64_t rows_vec_cond_filtered = 0; int64_t rows_short_circuit_cond_filtered = 0; + int64_t rows_common_expr_filtered = 0; int64_t vec_cond_input_rows = 0; int64_t short_circuit_cond_input_rows = 0; int64_t rows_vec_del_cond_filtered = 0; diff --git a/be/src/olap/predicate_creator.h b/be/src/olap/predicate_creator.h index 742336ec777480..efe92c6dbd264c 100644 --- a/be/src/olap/predicate_creator.h +++ b/be/src/olap/predicate_creator.h @@ -23,7 +23,6 @@ #include "exec/olap_utils.h" #include "exprs/create_predicate_function.h" #include "exprs/hybrid_set.h" -#include "olap/bloom_filter_predicate.h" #include "olap/column_predicate.h" #include "olap/comparison_predicate.h" #include "olap/in_list_predicate.h" diff --git a/be/src/olap/reader.cpp b/be/src/olap/reader.cpp index e571b9d1c32fae..eab24a8ea81f92 100644 --- a/be/src/olap/reader.cpp +++ b/be/src/olap/reader.cpp @@ -490,11 +490,6 @@ Status TabletReader::_init_conditions_param(const ReaderParams& read_params) { } } - // Only key column bloom filter will push down to storage engine - for (const auto& filter : read_params.bloom_filters) { - _col_predicates.emplace_back(_parse_to_predicate(filter)); - } - for (const auto& filter : read_params.bitmap_filters) { _col_predicates.emplace_back(_parse_to_predicate(filter)); } @@ -568,17 +563,6 @@ void TabletReader::_init_conditions_param_except_leafnode_of_andnode( } } -ColumnPredicate* TabletReader::_parse_to_predicate( - const std::pair>& bloom_filter) { - int32_t index = _tablet_schema->field_index(bloom_filter.first); - if (index < 0) { - return nullptr; - } - const TabletColumn& column = _tablet_schema->column(index); - return create_column_predicate(index, bloom_filter.second, column.type(), - _reader_context.runtime_state->be_exec_version(), &column); -} - ColumnPredicate* TabletReader::_parse_to_predicate( const std::pair>& in_filter) { int32_t index = _tablet_schema->field_index(in_filter.first); diff --git a/be/src/olap/reader.h b/be/src/olap/reader.h index b0d5ed1fa280c9..11806f5ca9cd84 100644 --- a/be/src/olap/reader.h +++ b/be/src/olap/reader.h @@ -240,9 +240,6 @@ class TabletReader { void _init_conditions_param_except_leafnode_of_andnode(const ReaderParams& read_params); - ColumnPredicate* _parse_to_predicate( - const std::pair>& bloom_filter); - ColumnPredicate* _parse_to_predicate( const std::pair>& bitmap_filter); diff --git a/be/src/olap/rowset/segment_v2/segment_iterator.cpp b/be/src/olap/rowset/segment_v2/segment_iterator.cpp index b5e7aa7d4bf476..a86d1681442d26 100644 --- a/be/src/olap/rowset/segment_v2/segment_iterator.cpp +++ b/be/src/olap/rowset/segment_v2/segment_iterator.cpp @@ -38,7 +38,6 @@ #include "common/object_pool.h" #include "common/status.h" #include "io/io_common.h" -#include "olap/bloom_filter_predicate.h" #include "olap/column_predicate.h" #include "olap/field.h" #include "olap/iterators.h" @@ -2059,7 +2058,9 @@ Status SegmentIterator::_execute_common_expr(uint16_t* sel_rowid_idx, uint16_t& RETURN_IF_ERROR(vectorized::VExprContext::execute_conjuncts_and_filter_block( _common_expr_ctxs_push_down, block, _columns_to_filter, prev_columns, filter)); + const auto origin_size = selected_size; selected_size = _evaluate_common_expr_filter(sel_rowid_idx, selected_size, filter); + _opts.stats->rows_common_expr_filtered += (origin_size - selected_size); return Status::OK(); } diff --git a/be/src/pipeline/exec/olap_scan_operator.cpp b/be/src/pipeline/exec/olap_scan_operator.cpp index b66157d567f4fc..785e2c0aa17b9e 100644 --- a/be/src/pipeline/exec/olap_scan_operator.cpp +++ b/be/src/pipeline/exec/olap_scan_operator.cpp @@ -72,6 +72,8 @@ Status OlapScanLocalState::_init_profile() { ADD_COUNTER(_segment_profile, "RowsVectorPredInput", TUnit::UNIT); _rows_short_circuit_cond_input_counter = ADD_COUNTER(_segment_profile, "RowsShortCircuitPredInput", TUnit::UNIT); + _rows_common_expr_filtered_counter = + ADD_COUNTER(_segment_profile, "RowsCommonExprFiltered", TUnit::UNIT); _vec_cond_timer = ADD_TIMER(_segment_profile, "VectorPredEvalTime"); _short_cond_timer = ADD_TIMER(_segment_profile, "ShortPredEvalTime"); _expr_filter_timer = ADD_TIMER(_segment_profile, "ExprFilterEvalTime"); diff --git a/be/src/pipeline/exec/olap_scan_operator.h b/be/src/pipeline/exec/olap_scan_operator.h index 0527fa6f44d484..d3c66581393a22 100644 --- a/be/src/pipeline/exec/olap_scan_operator.h +++ b/be/src/pipeline/exec/olap_scan_operator.h @@ -114,6 +114,7 @@ class OlapScanLocalState final : public ScanLocalState { RuntimeProfile::Counter* _rows_short_circuit_cond_filtered_counter = nullptr; RuntimeProfile::Counter* _rows_vec_cond_input_counter = nullptr; RuntimeProfile::Counter* _rows_short_circuit_cond_input_counter = nullptr; + RuntimeProfile::Counter* _rows_common_expr_filtered_counter = nullptr; RuntimeProfile::Counter* _vec_cond_timer = nullptr; RuntimeProfile::Counter* _short_cond_timer = nullptr; RuntimeProfile::Counter* _expr_filter_timer = nullptr; diff --git a/be/src/pipeline/exec/scan_operator.cpp b/be/src/pipeline/exec/scan_operator.cpp index 601bf5b8b9f340..4a1d51240057c4 100644 --- a/be/src/pipeline/exec/scan_operator.cpp +++ b/be/src/pipeline/exec/scan_operator.cpp @@ -356,9 +356,6 @@ Status ScanLocalState::_normalize_predicate( RETURN_IF_PUSH_DOWN( _normalize_bitmap_filter(cur_expr, context, slot, &pdt), status); - RETURN_IF_PUSH_DOWN( - _normalize_bloom_filter(cur_expr, context, slot, &pdt), - status); if (state()->enable_function_pushdown()) { RETURN_IF_PUSH_DOWN(_normalize_function_filters( cur_expr, context, slot, &pdt), @@ -431,23 +428,6 @@ Status ScanLocalState::_normalize_predicate( return Status::OK(); } -template -Status ScanLocalState::_normalize_bloom_filter(vectorized::VExpr* expr, - vectorized::VExprContext* expr_ctx, - SlotDescriptor* slot, - vectorized::VScanNode::PushDownType* pdt) { - if (TExprNodeType::BLOOM_PRED == expr->node_type()) { - DCHECK(expr->children().size() == 1); - vectorized::VScanNode::PushDownType temp_pdt = _should_push_down_bloom_filter(); - if (temp_pdt != vectorized::VScanNode::PushDownType::UNACCEPTABLE) { - _filter_predicates.bloom_filters.emplace_back(slot->col_name(), - expr->get_bloom_filter_func()); - *pdt = temp_pdt; - } - } - return Status::OK(); -} - template Status ScanLocalState::_normalize_bitmap_filter(vectorized::VExpr* expr, vectorized::VExprContext* expr_ctx, diff --git a/be/src/pipeline/exec/scan_operator.h b/be/src/pipeline/exec/scan_operator.h index 68d006006f6989..8ee9b4b5b408f2 100644 --- a/be/src/pipeline/exec/scan_operator.h +++ b/be/src/pipeline/exec/scan_operator.h @@ -287,9 +287,6 @@ class ScanLocalState : public ScanLocalStateBase { Status _eval_const_conjuncts(vectorized::VExpr* vexpr, vectorized::VExprContext* expr_ctx, vectorized::VScanNode::PushDownType* pdt); - Status _normalize_bloom_filter(vectorized::VExpr* expr, vectorized::VExprContext* expr_ctx, - SlotDescriptor* slot, vectorized::VScanNode::PushDownType* pdt); - Status _normalize_bitmap_filter(vectorized::VExpr* expr, vectorized::VExprContext* expr_ctx, SlotDescriptor* slot, vectorized::VScanNode::PushDownType* pdt); diff --git a/be/src/vec/exec/scan/new_olap_scan_node.cpp b/be/src/vec/exec/scan/new_olap_scan_node.cpp index b7b3c5b7f7cb16..fca98e5f7667bb 100644 --- a/be/src/vec/exec/scan/new_olap_scan_node.cpp +++ b/be/src/vec/exec/scan/new_olap_scan_node.cpp @@ -134,6 +134,8 @@ Status NewOlapScanNode::_init_profile() { ADD_COUNTER(_segment_profile, "RowsVectorPredInput", TUnit::UNIT); _rows_short_circuit_cond_input_counter = ADD_COUNTER(_segment_profile, "RowsShortCircuitPredInput", TUnit::UNIT); + _rows_common_expr_filtered_counter = + ADD_COUNTER(_segment_profile, "RowsCommonExprFiltered", TUnit::UNIT); _vec_cond_timer = ADD_TIMER(_segment_profile, "VectorPredEvalTime"); _short_cond_timer = ADD_TIMER(_segment_profile, "ShortPredEvalTime"); _expr_filter_timer = ADD_TIMER(_segment_profile, "ExprFilterEvalTime"); diff --git a/be/src/vec/exec/scan/new_olap_scan_node.h b/be/src/vec/exec/scan/new_olap_scan_node.h index 93039c6182ad6a..7a25d743c4ccc1 100644 --- a/be/src/vec/exec/scan/new_olap_scan_node.h +++ b/be/src/vec/exec/scan/new_olap_scan_node.h @@ -138,6 +138,7 @@ class NewOlapScanNode : public VScanNode { RuntimeProfile::Counter* _rows_short_circuit_cond_filtered_counter = nullptr; RuntimeProfile::Counter* _rows_vec_cond_input_counter = nullptr; RuntimeProfile::Counter* _rows_short_circuit_cond_input_counter = nullptr; + RuntimeProfile::Counter* _rows_common_expr_filtered_counter = nullptr; RuntimeProfile::Counter* _vec_cond_timer = nullptr; RuntimeProfile::Counter* _short_cond_timer = nullptr; RuntimeProfile::Counter* _expr_filter_timer = nullptr; diff --git a/be/src/vec/exec/scan/new_olap_scanner.cpp b/be/src/vec/exec/scan/new_olap_scanner.cpp index 980ee5b4cea262..7992ab1a4566bb 100644 --- a/be/src/vec/exec/scan/new_olap_scanner.cpp +++ b/be/src/vec/exec/scan/new_olap_scanner.cpp @@ -553,6 +553,7 @@ void NewOlapScanner::_update_counters_before_close() { COUNTER_UPDATE(Parent->_rows_vec_cond_input_counter, stats.vec_cond_input_rows); \ COUNTER_UPDATE(Parent->_rows_short_circuit_cond_input_counter, \ stats.short_circuit_cond_input_rows); \ + COUNTER_UPDATE(Parent->_rows_common_expr_filtered_counter, stats.rows_common_expr_filtered); \ for (auto& [id, info] : stats.filter_info) { \ Parent->add_filter_info(id, info); \ } \ diff --git a/be/src/vec/exec/scan/vscan_node.cpp b/be/src/vec/exec/scan/vscan_node.cpp index b743de4b141c83..0fb60b73d04c63 100644 --- a/be/src/vec/exec/scan/vscan_node.cpp +++ b/be/src/vec/exec/scan/vscan_node.cpp @@ -524,9 +524,6 @@ Status VScanNode::_normalize_predicate(const VExprSPtr& conjunct_expr_root, VExp RETURN_IF_PUSH_DOWN( _normalize_bitmap_filter(cur_expr, context, slot, &pdt), status); - RETURN_IF_PUSH_DOWN( - _normalize_bloom_filter(cur_expr, context, slot, &pdt), - status); if (_state->enable_function_pushdown()) { RETURN_IF_PUSH_DOWN(_normalize_function_filters( cur_expr, context, slot, &pdt), @@ -599,20 +596,6 @@ Status VScanNode::_normalize_predicate(const VExprSPtr& conjunct_expr_root, VExp return Status::OK(); } -Status VScanNode::_normalize_bloom_filter(VExpr* expr, VExprContext* expr_ctx, SlotDescriptor* slot, - PushDownType* pdt) { - if (TExprNodeType::BLOOM_PRED == expr->node_type()) { - DCHECK(expr->children().size() == 1); - PushDownType temp_pdt = _should_push_down_bloom_filter(); - if (temp_pdt != PushDownType::UNACCEPTABLE) { - _filter_predicates.bloom_filters.emplace_back(slot->col_name(), - expr->get_bloom_filter_func()); - *pdt = temp_pdt; - } - } - return Status::OK(); -} - Status VScanNode::_normalize_bitmap_filter(VExpr* expr, VExprContext* expr_ctx, SlotDescriptor* slot, PushDownType* pdt) { if (TExprNodeType::BITMAP_PRED == expr->node_type()) { diff --git a/be/src/vec/exec/scan/vscan_node.h b/be/src/vec/exec/scan/vscan_node.h index 73961f591332fb..5110ce18ac3ec1 100644 --- a/be/src/vec/exec/scan/vscan_node.h +++ b/be/src/vec/exec/scan/vscan_node.h @@ -365,9 +365,6 @@ class VScanNode : public ExecNode, public RuntimeFilterConsumer { VExprSPtr& output_expr); Status _eval_const_conjuncts(VExpr* vexpr, VExprContext* expr_ctx, PushDownType* pdt); - Status _normalize_bloom_filter(VExpr* expr, VExprContext* expr_ctx, SlotDescriptor* slot, - PushDownType* pdt); - Status _normalize_bitmap_filter(VExpr* expr, VExprContext* expr_ctx, SlotDescriptor* slot, PushDownType* pdt); From 5e9a23e6439aad102550389d61ffc2c1cceb86af Mon Sep 17 00:00:00 2001 From: meiyi Date: Tue, 7 Nov 2023 19:41:44 +0800 Subject: [PATCH 13/88] [fix](prepare statement) Not supported such prepared statement if prepare a forward master sql (#26512) --- .../src/main/java/org/apache/doris/qe/StmtExecutor.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java index 82d6188bfce847..ec3a5a79586644 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java @@ -531,6 +531,9 @@ private void executeByNereids(TUniqueId queryId) throws Exception { if (logicalPlan instanceof Forward) { redirectStatus = ((Forward) logicalPlan).toRedirectStatus(); if (isForwardToMaster()) { + if (context.getCommand() == MysqlCommand.COM_STMT_PREPARE) { + throw new UserException("Forward master command is not supported for prepare statement"); + } if (isProxy) { // This is already a stmt forwarded from other FE. // If we goes here, means we can't find a valid Master FE(some error happens). @@ -704,6 +707,9 @@ public void executeByLegacy(TUniqueId queryId) throws Exception { queryAnalysisSpan.end(); } if (isForwardToMaster()) { + if (context.getCommand() == MysqlCommand.COM_STMT_PREPARE) { + throw new UserException("Forward master command is not supported for prepare statement"); + } if (isProxy) { // This is already a stmt forwarded from other FE. // If goes here, which means we can't find a valid Master FE(some error happens). From 2be6c9ff7d8fd78bfd67f1eebbaeb4ca67707ead Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=B0=A2=E5=81=A5?= Date: Tue, 7 Nov 2023 20:05:40 +0800 Subject: [PATCH 14/88] [enhancement](Nereids): when the DPhyper failed, roll back to cascades without join reorder (#26390) when the DPhyper failed, roll back to cascades without join reorder --- .../nereids/jobs/joinorder/JoinOrderJob.java | 26 +++++++++------- .../joinorder/hypergraph/GraphSimplifier.java | 30 +++++++++---------- .../jobs/joinorder/hypergraph/HyperGraph.java | 6 ++++ .../hypergraph/receiver/Counter.java | 4 +++ .../hypergraph/receiver/PlanReceiver.java | 6 +++- .../org/apache/doris/qe/SessionVariable.java | 4 +++ .../hypergraph/GraphSimplifierTest.java | 17 +++++++++++ .../nereids/sqltest/JoinOrderJobTest.java | 18 +++++++++++ 8 files changed, 85 insertions(+), 26 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/JoinOrderJob.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/JoinOrderJob.java index a48604dc027915..c81108b1c8409e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/JoinOrderJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/JoinOrderJob.java @@ -37,6 +37,8 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import com.google.common.collect.Lists; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.ArrayList; import java.util.BitSet; @@ -47,6 +49,7 @@ * Join Order job with DPHyp */ public class JoinOrderJob extends Job { + public static final Logger LOG = LogManager.getLogger(JoinOrderJob.class); private final Group group; private final Set otherProject = new HashSet<>(); @@ -87,20 +90,14 @@ private Group optimizeJoin(Group group) { int limit = 1000; PlanReceiver planReceiver = new PlanReceiver(this.context, limit, hyperGraph, group.getLogicalProperties().getOutputSet()); - SubgraphEnumerator subgraphEnumerator = new SubgraphEnumerator(planReceiver, hyperGraph); - if (!subgraphEnumerator.enumerate()) { - GraphSimplifier graphSimplifier = new GraphSimplifier(hyperGraph); - graphSimplifier.simplifyGraph(limit); - if (!subgraphEnumerator.enumerate()) { - throw new RuntimeException("DPHyp can not enumerate all sub graphs with limit=" + limit); - } + if (!tryEnumerateJoin(hyperGraph, planReceiver, limit)) { + return group; } Group optimized = planReceiver.getBestPlan(hyperGraph.getNodesMap()); - // For other projects, such as project constant or project nullable, we construct a new project above root - if (otherProject.size() != 0) { + if (!otherProject.isEmpty()) { otherProject.addAll(optimized.getLogicalExpression().getPlan().getOutput()); - LogicalProject logicalProject = new LogicalProject<>(new ArrayList<>(otherProject), + LogicalProject logicalProject = new LogicalProject<>(new ArrayList<>(otherProject), optimized.getLogicalExpression().getPlan()); GroupExpression groupExpression = new GroupExpression(logicalProject, Lists.newArrayList(group)); optimized = context.getCascadesContext().getMemo().copyInGroupExpression(groupExpression); @@ -108,6 +105,15 @@ private Group optimizeJoin(Group group) { return optimized; } + private boolean tryEnumerateJoin(HyperGraph hyperGraph, PlanReceiver planReceiver, int limit) { + SubgraphEnumerator subgraphEnumerator = new SubgraphEnumerator(planReceiver, hyperGraph); + if (!subgraphEnumerator.enumerate()) { + GraphSimplifier graphSimplifier = new GraphSimplifier(hyperGraph); + return graphSimplifier.simplifyGraph(limit) && subgraphEnumerator.enumerate(); + } + return true; + } + /** * build a hyperGraph for the root group * diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifier.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifier.java index aa92d0fe0059c6..291a6070ea59c7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifier.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifier.java @@ -392,26 +392,27 @@ private Optional makeSimplificationStep(int edgeIndex1, int } private Edge constructEdge(long leftNodes, Edge edge, long rightNodes) { + LogicalJoin join; if (graph.getEdges().size() > 64 * 63 / 8) { // If there are too many edges, it is advisable to return the "edge" directly // to avoid lengthy enumeration time. - return edge; - } - BitSet validEdgesMap = graph.getEdgesInOperator(leftNodes, rightNodes); - List hashConditions = validEdgesMap.stream() - .mapToObj(i -> graph.getEdge(i).getJoin().getHashJoinConjuncts()) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - List otherConditions = validEdgesMap.stream() - .mapToObj(i -> graph.getEdge(i).getJoin().getHashJoinConjuncts()) - .flatMap(Collection::stream) - .collect(Collectors.toList()); - LogicalJoin join = - edge.getJoin().withJoinConjuncts(hashConditions, otherConditions); + join = edge.getJoin(); + } else { + BitSet validEdgesMap = graph.getEdgesInOperator(leftNodes, rightNodes); + List hashConditions = validEdgesMap.stream() + .mapToObj(i -> graph.getEdge(i).getJoin().getHashJoinConjuncts()) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + List otherConditions = validEdgesMap.stream() + .mapToObj(i -> graph.getEdge(i).getJoin().getHashJoinConjuncts()) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + join = edge.getJoin().withJoinConjuncts(hashConditions, otherConditions); + } Edge newEdge = new Edge( join, - -1, edge.getLeftChildEdges(), edge.getRightChildEdges(), edge.getSubTreeNodes()); + edge.getIndex(), edge.getLeftChildEdges(), edge.getRightChildEdges(), edge.getSubTreeNodes()); newEdge.setLeftRequiredNodes(edge.getLeftRequiredNodes()); newEdge.setRightRequiredNodes(edge.getRightRequiredNodes()); newEdge.addLeftNode(leftNodes); @@ -462,7 +463,6 @@ private double calCost(Edge edge, long leftBitmap, long rightBitmap) { // if the left and right is overlapping, just return null. Preconditions.checkArgument( cacheStats.containsKey(bitmap1) && cacheStats.containsKey(bitmap2) && cacheStats.containsKey(bitmap3)); - // construct new Edge long newLeft = LongBitmap.newBitmapUnion(bitmap1, bitmap2); if (LongBitmap.isOverlap(newLeft, bitmap3)) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraph.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraph.java index 23ca17825b5637..a1ca130452f2f3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraph.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/HyperGraph.java @@ -316,10 +316,16 @@ public void modifyEdge(int edgeIndex, long newLeft, long newRight) { // For these nodes that are only in the old edge, we need remove the edge from them // For these nodes that are only in the new edge, we need to add the edge to them Edge edge = edges.get(edgeIndex); + if (treeEdgesCache.containsKey(edge.getReferenceNodes())) { + treeEdgesCache.get(edge.getReferenceNodes()).set(edgeIndex, false); + } updateEdges(edge, edge.getLeftExtendedNodes(), newLeft); updateEdges(edge, edge.getRightExtendedNodes(), newRight); edges.get(edgeIndex).setLeftExtendedNodes(newLeft); edges.get(edgeIndex).setRightExtendedNodes(newRight); + if (treeEdgesCache.containsKey(edge.getReferenceNodes())) { + treeEdgesCache.get(edge.getReferenceNodes()).set(edgeIndex, true); + } } private void updateEdges(Edge edge, long oldNodes, long newNodes) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/Counter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/Counter.java index 4bb57fb580223b..d14ce91469b90f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/Counter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/Counter.java @@ -95,4 +95,8 @@ public HashMap getAllCount() { public int getLimit() { return limit; } + + public int getEmitCount() { + return emitCount; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/PlanReceiver.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/PlanReceiver.java index 099118c65e6d6a..31a6786ac3ef11 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/PlanReceiver.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/receiver/PlanReceiver.java @@ -46,6 +46,7 @@ import org.apache.doris.nereids.util.ExpressionUtils; import org.apache.doris.nereids.util.JoinUtils; import org.apache.doris.nereids.util.PlanUtils; +import org.apache.doris.qe.ConnectContext; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; @@ -76,6 +77,8 @@ public class PlanReceiver implements AbstractReceiver { HyperGraph hyperGraph; final Set finalOutputs; + long startTime = System.currentTimeMillis(); + long timeLimit = ConnectContext.get().getSessionVariable().joinReorderTimeLimit; public PlanReceiver(JobContext jobContext, int limit, HyperGraph hyperGraph, Set outputs) { this.jobContext = jobContext; @@ -104,7 +107,7 @@ public boolean emitCsgCmp(long left, long right, List edges) { processMissedEdges(left, right, edges); emitCount += 1; - if (emitCount > limit) { + if (emitCount > limit || System.currentTimeMillis() - startTime > timeLimit) { return false; } @@ -272,6 +275,7 @@ public void reset() { usdEdges.clear(); complexProjectMap.clear(); complexProjectMap.putAll(hyperGraph.getComplexProject()); + startTime = System.currentTimeMillis(); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java index c2062762e6c7e8..1bf6791298b626 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java @@ -346,6 +346,7 @@ public class SessionVariable implements Serializable, Writable { public static final String MAX_TABLE_COUNT_USE_CASCADES_JOIN_REORDER = "max_table_count_use_cascades_join_reorder"; public static final int MIN_JOIN_REORDER_TABLE_COUNT = 2; + public static final String JOIN_REORDER_TIME_LIMIT = "join_order_time_limit"; public static final String SHOW_USER_DEFAULT_ROLE = "show_user_default_role"; public static final String ENABLE_MINIDUMP = "enable_minidump"; @@ -1106,6 +1107,9 @@ public void setMaxJoinNumberOfReorder(int maxJoinNumberOfReorder) { @VariableMgr.VarAttr(name = MAX_TABLE_COUNT_USE_CASCADES_JOIN_REORDER, needForward = true) public int maxTableCountUseCascadesJoinReorder = 10; + @VariableMgr.VarAttr(name = JOIN_REORDER_TIME_LIMIT, needForward = true) + public long joinReorderTimeLimit = 1000; + // If this is true, the result of `show roles` will return all user default role @VariableMgr.VarAttr(name = SHOW_USER_DEFAULT_ROLE, needForward = true) public boolean showUserDefaultRole = false; diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifierTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifierTest.java index 79859ccf7aa738..402cc1b64da2ed 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifierTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/jobs/joinorder/hypergraph/GraphSimplifierTest.java @@ -250,6 +250,23 @@ void testLimit() { } } + @Disabled + @Test + void test64Clique() { + HyperGraph hyperGraph = new HyperGraphBuilder(Sets.newHashSet(JoinType.INNER_JOIN)) + .randomBuildWith(64, 67); + Counter counter = new Counter(); + SubgraphEnumerator subgraphEnumerator = new SubgraphEnumerator(counter, hyperGraph); + GraphSimplifier graphSimplifier = new GraphSimplifier(hyperGraph); + graphSimplifier.simplifyGraph(1); + + for (Edge edge : hyperGraph.getEdges()) { + System.out.println(edge); + } + Assertions.assertTrue(subgraphEnumerator.enumerate()); + System.out.println(counter.getEmitCount()); + } + @Disabled @Test void benchGraphSimplifier() { diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/sqltest/JoinOrderJobTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/sqltest/JoinOrderJobTest.java index 259fb24ece7c3a..73c3a6145200ee 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/sqltest/JoinOrderJobTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/sqltest/JoinOrderJobTest.java @@ -19,13 +19,16 @@ import org.apache.doris.nereids.CascadesContext; import org.apache.doris.nereids.memo.Memo; +import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.logical.LogicalProject; import org.apache.doris.nereids.util.HyperGraphBuilder; import org.apache.doris.nereids.util.MemoTestUtils; import org.apache.doris.nereids.util.PlanChecker; +import com.google.common.collect.Sets; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; public class JoinOrderJobTest extends SqlTestBase { @@ -141,4 +144,19 @@ protected void test64TableJoin() { .optimize() .getBestPlanTree(); } + + @Disabled + @Test + void test64CliqueJoin() { + HyperGraphBuilder hyperGraphBuilder = new HyperGraphBuilder(Sets.newHashSet(JoinType.INNER_JOIN)); + Plan plan = hyperGraphBuilder + .randomBuildPlanWith(64, 64 * 63 / 2); + plan = new LogicalProject(plan.getOutput(), plan); + CascadesContext cascadesContext = MemoTestUtils.createCascadesContext(connectContext, plan); + hyperGraphBuilder.initStats(cascadesContext); + PlanChecker.from(cascadesContext) + .rewrite() + .dpHypOptimize() + .getBestPlanTree(); + } } From ceccc451faabf1b26a7bef9de0206c40a554ed55 Mon Sep 17 00:00:00 2001 From: jakevin Date: Tue, 7 Nov 2023 21:46:54 +0800 Subject: [PATCH 15/88] [enhancement](Nereids): add LOG info to show the phase of NereidsPlanner. (#26538) Add LOG info to show the phase of NereidsPlanner, we can use these info to debug. --- .../main/java/org/apache/doris/nereids/NereidsPlanner.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java index 436ecae55209f9..fa25c5a6d90bd6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/NereidsPlanner.java @@ -264,22 +264,28 @@ private void initCascadesContext(LogicalPlan plan, PhysicalProperties requirePro } private void analyze() { + LOG.info("Start analyze plan"); cascadesContext.newAnalyzer().analyze(); NereidsTracer.logImportantTime("EndAnalyzePlan"); + LOG.info("End analyze plan"); } /** * Logical plan rewrite based on a series of heuristic rules. */ private void rewrite() { + LOG.info("Start rewrite plan"); Rewriter.getWholeTreeRewriter(cascadesContext).execute(); NereidsTracer.logImportantTime("EndRewritePlan"); + LOG.info("End rewrite plan"); } // DependsRules: EnsureProjectOnTopJoin.class private void optimize() { + LOG.info("Start optimize plan"); new Optimizer(cascadesContext).execute(); NereidsTracer.logImportantTime("EndOptimizePlan"); + LOG.info("End optimize plan"); } private PhysicalPlan postProcess(PhysicalPlan physicalPlan) { From 5d80e7dc2fe7a9cc80cc26244146d5dda8070908 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Tue, 7 Nov 2023 22:11:44 +0800 Subject: [PATCH 16/88] [Improvement](pipelineX) Improve local exchange on pipelineX engine (#26464) --- .../pipeline/exec/exchange_sink_operator.cpp | 16 +++---- be/src/pipeline/exec/exchange_sink_operator.h | 29 ++++++++++-- be/src/runtime/runtime_state.h | 4 ++ be/src/vec/runtime/vdata_stream_recvr.cpp | 46 +++++++++++++------ be/src/vec/runtime/vdata_stream_recvr.h | 22 +++++---- be/src/vec/sink/vdata_stream_sender.h | 12 ++--- 6 files changed, 85 insertions(+), 44 deletions(-) diff --git a/be/src/pipeline/exec/exchange_sink_operator.cpp b/be/src/pipeline/exec/exchange_sink_operator.cpp index b5cceb5a291779..e6bcccbabb2d7b 100644 --- a/be/src/pipeline/exec/exchange_sink_operator.cpp +++ b/be/src/pipeline/exec/exchange_sink_operator.cpp @@ -192,15 +192,14 @@ Status ExchangeSinkLocalState::init(RuntimeState* state, LocalSinkStateInfo& inf ADD_CHILD_TIMER(_profile, "WaitForBroadcastBuffer", timer_name); } else if (local_size > 0) { size_t dep_id = 0; - _channels_dependency.resize(local_size); + _local_channels_dependency.resize(local_size); _wait_channel_timer.resize(local_size); auto deps_for_channels = AndDependency::create_shared(_parent->operator_id()); for (auto channel : channels) { if (channel->is_local()) { - _channels_dependency[dep_id] = - ChannelDependency::create_shared(_parent->operator_id()); - channel->set_dependency(_channels_dependency[dep_id]); - deps_for_channels->add_child(_channels_dependency[dep_id]); + _local_channels_dependency[dep_id] = channel->get_local_channel_dependency(); + DCHECK(_local_channels_dependency[dep_id] != nullptr); + deps_for_channels->add_child(_local_channels_dependency[dep_id]); _wait_channel_timer[dep_id] = ADD_CHILD_TIMER(_profile, "WaitForLocalExchangeBuffer", timer_name); dep_id++; @@ -428,7 +427,8 @@ Status ExchangeSinkOperatorX::serialize_block(ExchangeSinkLocalState& state, vec { SCOPED_TIMER(state.serialize_batch_timer()); dest->Clear(); - size_t uncompressed_bytes = 0, compressed_bytes = 0; + size_t uncompressed_bytes = 0; + size_t compressed_bytes = 0; RETURN_IF_ERROR(src->serialize(_state->be_exec_version(), dest, &uncompressed_bytes, &compressed_bytes, _compression_type, _transfer_large_data_by_brpc)); @@ -521,9 +521,9 @@ Status ExchangeSinkLocalState::close(RuntimeState* state, Status exec_status) { COUNTER_UPDATE(_wait_broadcast_buffer_timer, _broadcast_dependency->write_watcher_elapse_time()); } - for (size_t i = 0; i < _channels_dependency.size(); i++) { + for (size_t i = 0; i < _local_channels_dependency.size(); i++) { COUNTER_UPDATE(_wait_channel_timer[i], - _channels_dependency[i]->write_watcher_elapse_time()); + _local_channels_dependency[i]->write_watcher_elapse_time()); } _sink_buffer->update_profile(profile()); _sink_buffer->close(); diff --git a/be/src/pipeline/exec/exchange_sink_operator.h b/be/src/pipeline/exec/exchange_sink_operator.h index 815d3930577d15..2b42d28958a5bc 100644 --- a/be/src/pipeline/exec/exchange_sink_operator.h +++ b/be/src/pipeline/exec/exchange_sink_operator.h @@ -113,11 +113,30 @@ class BroadcastDependency final : public WriteDependency { std::atomic _available_block; }; -class ChannelDependency final : public WriteDependency { +/** + * We use this to control the execution for local exchange. + * +---------------+ +---------------+ +---------------+ + * | ExchangeSink1 | | ExchangeSink2 | | ExchangeSink3 | + * +---------------+ +---------------+ +---------------+ + * | | | + * | +----------------------------+----------------------------------+ | + * +----+------------------|------------------------------------------+ | | + * | | +------------------------|--------------------|------------+-----+ + * Dependency 1-1 | Dependency 2-1 | Dependency 3-1 | Dependency 1-2 | Dependency 2-2 | Dependency 3-2 | + * +----------------------------------------------+ +----------------------------------------------+ + * | queue1 queue2 queue3 | | queue1 queue2 queue3 | + * | LocalRecvr | | LocalRecvr | + * +----------------------------------------------+ +----------------------------------------------+ + * +-----------------+ +------------------+ + * | ExchangeSource1 | | ExchangeSource2 | + * +-----------------+ +------------------+ + */ +class LocalExchangeChannelDependency final : public WriteDependency { public: - ENABLE_FACTORY_CREATOR(ChannelDependency); - ChannelDependency(int id) : WriteDependency(id, "ChannelDependency") {} - ~ChannelDependency() override = default; + ENABLE_FACTORY_CREATOR(LocalExchangeChannelDependency); + LocalExchangeChannelDependency(int id) + : WriteDependency(id, "LocalExchangeChannelDependency") {} + ~LocalExchangeChannelDependency() override = default; void* shared_state() override { return nullptr; } }; @@ -209,7 +228,7 @@ class ExchangeSinkLocalState final : public PipelineXSinkLocalState<> { std::shared_ptr _queue_dependency = nullptr; std::shared_ptr _exchange_sink_dependency = nullptr; std::shared_ptr _broadcast_dependency = nullptr; - std::vector> _channels_dependency; + std::vector> _local_channels_dependency; std::unique_ptr _partitioner; int _partition_count; }; diff --git a/be/src/runtime/runtime_state.h b/be/src/runtime/runtime_state.h index 1c20725cd33481..805951e34e3b56 100644 --- a/be/src/runtime/runtime_state.h +++ b/be/src/runtime/runtime_state.h @@ -329,6 +329,10 @@ class RuntimeState { return _query_options.__isset.enable_pipeline_engine && _query_options.enable_pipeline_engine; } + bool enable_pipeline_x_exec() const { + return _query_options.__isset.enable_pipeline_x_engine && + _query_options.enable_pipeline_x_engine; + } bool enable_local_shuffle() const { return _query_options.__isset.enable_local_shuffle && _query_options.enable_local_shuffle; } diff --git a/be/src/vec/runtime/vdata_stream_recvr.cpp b/be/src/vec/runtime/vdata_stream_recvr.cpp index b842cbeea48e62..9384d4abbfc627 100644 --- a/be/src/vec/runtime/vdata_stream_recvr.cpp +++ b/be/src/vec/runtime/vdata_stream_recvr.cpp @@ -100,7 +100,12 @@ Status VDataStreamRecvr::SenderQueue::_inner_get_batch_without_lock(Block* block _recvr->update_blocks_memory_usage(-block_byte_size); _block_queue.pop_front(); if (_block_queue.size() == 0 && _dependency) { - _dependency->block_reading(); + if (!_is_cancelled && _num_remaining_senders > 0) { + _dependency->block_reading(); + } + for (auto& it : _local_channel_dependency) { + it->set_ready_for_write(); + } } if (!_pending_closures.empty()) { @@ -350,6 +355,14 @@ VDataStreamRecvr::VDataStreamRecvr( std::make_unique("VDataStreamRecvr:" + print_id(_fragment_instance_id)); SCOPED_CONSUME_MEM_TRACKER(_mem_tracker.get()); + if (state->enable_pipeline_x_exec()) { + _sender_to_local_channel_dependency.resize(num_senders); + for (size_t i = 0; i < num_senders; i++) { + _sender_to_local_channel_dependency[i] = + pipeline::LocalExchangeChannelDependency::create_shared(_dest_node_id); + } + } + // Create one queue per sender if is_merging is true. int num_queues = is_merging ? num_senders : 1; _sender_queues.reserve(num_queues); @@ -358,6 +371,16 @@ VDataStreamRecvr::VDataStreamRecvr( SenderQueue* queue = nullptr; if (_enable_pipeline) { queue = _sender_queue_pool.add(new PipSenderQueue(this, num_sender_per_queue, profile)); + if (state->enable_pipeline_x_exec()) { + auto dependencies = + is_merging + ? std::vector> {_sender_to_local_channel_dependency + [i]} + : _sender_to_local_channel_dependency; + queue->set_local_channel_dependency(dependencies); + } } else { queue = _sender_queue_pool.add(new SenderQueue(this, num_sender_per_queue, profile)); } @@ -424,11 +447,11 @@ bool VDataStreamRecvr::sender_queue_empty(int sender_id) { return _sender_queues[use_sender_id]->queue_empty(); } -void VDataStreamRecvr::set_dependency(std::shared_ptr dependency) { - _dependency = dependency; - for (auto& queue : _sender_queues) { - queue->set_channel_dependency(dependency); - } +std::shared_ptr +VDataStreamRecvr::get_local_channel_dependency(int sender_id) { + DCHECK_GT(_sender_to_local_channel_dependency.size(), sender_id); + DCHECK(_sender_to_local_channel_dependency[sender_id] != nullptr); + return _sender_to_local_channel_dependency[sender_id]; } bool VDataStreamRecvr::ready_to_read() { @@ -482,13 +505,6 @@ void VDataStreamRecvr::cancel_stream(Status exec_status) { void VDataStreamRecvr::update_blocks_memory_usage(int64_t size) { _blocks_memory_usage->add(size); _blocks_memory_usage_current_value = _blocks_memory_usage->current_value(); - if (_dependency && size > 0 && - _blocks_memory_usage_current_value > config::exchg_node_buffer_size_bytes && !_is_closed) { - _dependency->block_writing(); - } else if (_dependency && size < 0 && - _blocks_memory_usage_current_value <= config::exchg_node_buffer_size_bytes) { - _dependency->set_ready_for_write(); - } } void VDataStreamRecvr::close() { @@ -496,8 +512,8 @@ void VDataStreamRecvr::close() { return; } _is_closed = true; - if (_dependency) { - _dependency->set_ready_for_write(); + for (auto& it : _sender_to_local_channel_dependency) { + it->set_ready_for_write(); } for (int i = 0; i < _sender_queues.size(); ++i) { _sender_queues[i]->close(); diff --git a/be/src/vec/runtime/vdata_stream_recvr.h b/be/src/vec/runtime/vdata_stream_recvr.h index b2fd6afdc7f207..2f5c88301e2217 100644 --- a/be/src/vec/runtime/vdata_stream_recvr.h +++ b/be/src/vec/runtime/vdata_stream_recvr.h @@ -59,7 +59,7 @@ class RuntimeState; namespace pipeline { struct ExchangeDataDependency; -class ChannelDependency; +class LocalExchangeChannelDependency; } // namespace pipeline namespace vectorized { @@ -125,7 +125,8 @@ class VDataStreamRecvr { bool is_closed() const { return _is_closed; } - void set_dependency(std::shared_ptr dependency); + std::shared_ptr get_local_channel_dependency( + int sender_id); private: void update_blocks_memory_usage(int64_t size); @@ -183,7 +184,8 @@ class VDataStreamRecvr { std::shared_ptr _sub_plan_query_statistics_recvr; bool _enable_pipeline; - std::shared_ptr _dependency; + std::vector> + _sender_to_local_channel_dependency; }; class ThreadClosure : public google::protobuf::Closure { @@ -201,6 +203,12 @@ class VDataStreamRecvr::SenderQueue { virtual ~SenderQueue(); + void set_local_channel_dependency( + std::vector>& + local_channel_dependency) { + _local_channel_dependency = local_channel_dependency; + } + virtual bool should_wait(); virtual Status get_batch(Block* next_block, bool* eos); @@ -225,10 +233,6 @@ class VDataStreamRecvr::SenderQueue { _dependency = dependency; } - void set_channel_dependency(std::shared_ptr channel_dependency) { - _channel_dependency = channel_dependency; - } - protected: Status _inner_get_batch_without_lock(Block* block, bool* eos); @@ -251,7 +255,8 @@ class VDataStreamRecvr::SenderQueue { std::unordered_map> _local_closure; std::shared_ptr _dependency = nullptr; - std::shared_ptr _channel_dependency = nullptr; + std::vector> + _local_channel_dependency; }; class VDataStreamRecvr::PipSenderQueue : public SenderQueue { @@ -270,5 +275,6 @@ class VDataStreamRecvr::PipSenderQueue : public SenderQueue { void add_block(Block* block, bool use_move) override; }; + } // namespace vectorized } // namespace doris diff --git a/be/src/vec/sink/vdata_stream_sender.h b/be/src/vec/sink/vdata_stream_sender.h index a09cb4b7d47f86..30a55f13296543 100644 --- a/be/src/vec/sink/vdata_stream_sender.h +++ b/be/src/vec/sink/vdata_stream_sender.h @@ -65,7 +65,7 @@ enum CompressionTypePB : int; namespace pipeline { class ExchangeSinkOperator; class ExchangeSinkOperatorX; -class ChannelDependency; +class LocalExchangeChannelDependency; } // namespace pipeline namespace vectorized { @@ -310,11 +310,6 @@ class Channel { bool is_local() const { return _is_local; } - VDataStreamRecvr* local_recvr() { - DCHECK(_is_local && _local_recvr != nullptr); - return _local_recvr.get(); - } - virtual void ch_roll_pb_block(); bool can_write() { @@ -557,11 +552,12 @@ class PipChannel final : public Channel { return _closure.get(); } - void set_dependency(std::shared_ptr dependency) { + std::shared_ptr get_local_channel_dependency() { if (!Channel::_local_recvr) { throw Exception(ErrorCode::INTERNAL_ERROR, "_local_recvr is null"); } - Channel::_local_recvr->set_dependency(dependency); + return Channel::_local_recvr->get_local_channel_dependency( + Channel::_parent->sender_id()); } private: From 3faf3b41187f6125881ee5391ecffe1a1239844a Mon Sep 17 00:00:00 2001 From: Gavin Chou Date: Tue, 7 Nov 2023 22:33:02 +0800 Subject: [PATCH 17/88] [chore] Print FE version even if it has been started (#26427) In the previous implementation, `bin/start_fe.sh --version` will complain that "Frontend running as process xxx. Stop it first." To show version 1. `bin/start_fe.sh --version` will print version info to fe.out 2. `bin/start_fe.sh --console --version` will print version info to stdout --- bin/start_fe.sh | 5 ++++- .../main/java/org/apache/doris/DorisFE.java | 19 ++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/bin/start_fe.sh b/bin/start_fe.sh index 14f7624b8d682d..56f78af697a991 100755 --- a/bin/start_fe.sh +++ b/bin/start_fe.sh @@ -218,7 +218,7 @@ export CLASSPATH="${DORIS_HOME}/conf:${CLASSPATH}:${DORIS_HOME}/lib" pidfile="${PID_DIR}/fe.pid" -if [[ -f "${pidfile}" ]]; then +if [[ -f "${pidfile}" ]] && [[ "${OPT_VERSION}" == "" ]]; then if kill -0 "$(cat "${pidfile}")" >/dev/null 2>&1; then echo "Frontend running as process $(cat "${pidfile}"). Stop it first." exit 1 @@ -258,4 +258,7 @@ else ${LIMIT:+${LIMIT}} "${JAVA}" ${final_java_opt:+${final_java_opt}} -XX:-OmitStackTraceInFastThrow -XX:OnOutOfMemoryError="kill -9 %p" ${coverage_opt:+${coverage_opt}} org.apache.doris.DorisFE ${HELPER:+${HELPER}} ${OPT_VERSION:+${OPT_VERSION}} "$@" >>"${LOG_DIR}/fe.out" 2>&1 "${pidfile}" diff --git a/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java b/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java index 1e9d5de054b3c5..b76f609f74991f 100755 --- a/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java +++ b/fe/fe-core/src/main/java/org/apache/doris/DorisFE.java @@ -101,6 +101,11 @@ public static void start(String dorisHomeDir, String pidDir, String[] args, Star CommandLineOptions cmdLineOpts = parseArgs(args); try { + if (cmdLineOpts.isVersion()) { + printVersion(); + System.exit(0); + } + // pid file if (!createAndLockPidFile(pidDir + "/fe.pid")) { throw new IOException("pid file is already locked."); @@ -371,13 +376,17 @@ private static CommandLineOptions parseArgs(String[] args) { return new CommandLineOptions(false, null, null, ""); } + private static void printVersion() { + System.out.println("Build version: " + Version.DORIS_BUILD_VERSION); + System.out.println("Build time: " + Version.DORIS_BUILD_TIME); + System.out.println("Build info: " + Version.DORIS_BUILD_INFO); + System.out.println("Build hash: " + Version.DORIS_BUILD_HASH); + System.out.println("Java compile version: " + Version.DORIS_JAVA_COMPILE_VERSION); + } + private static void checkCommandLineOptions(CommandLineOptions cmdLineOpts) { if (cmdLineOpts.isVersion()) { - System.out.println("Build version: " + Version.DORIS_BUILD_VERSION); - System.out.println("Build time: " + Version.DORIS_BUILD_TIME); - System.out.println("Build info: " + Version.DORIS_BUILD_INFO); - System.out.println("Build hash: " + Version.DORIS_BUILD_HASH); - System.out.println("Java compile version: " + Version.DORIS_JAVA_COMPILE_VERSION); + printVersion(); System.exit(0); } else if (cmdLineOpts.runBdbTools()) { BDBTool bdbTool = new BDBTool(Env.getCurrentEnv().getBdbDir(), cmdLineOpts.getBdbToolOpts()); From 32b36d3c9c73a34fb2308b879fdb62e9f054cad6 Mon Sep 17 00:00:00 2001 From: Kaijie Chen Date: Tue, 7 Nov 2023 22:41:20 +0800 Subject: [PATCH 18/88] [refactor](move-memtable) rename proto OpenStreamSink to OpenLoadStream (#26527) --- be/src/runtime/load_stream.cpp | 2 +- be/src/runtime/load_stream.h | 2 +- be/src/runtime/load_stream_mgr.cpp | 2 +- be/src/runtime/load_stream_mgr.h | 2 +- be/src/service/internal_service.cpp | 4 ++-- be/src/service/internal_service.h | 2 +- be/src/vec/sink/load_stream_stub.cpp | 4 ++-- be/test/runtime/load_stream_test.cpp | 8 ++++---- gensrc/proto/internal_service.proto | 6 +++--- 9 files changed, 16 insertions(+), 16 deletions(-) diff --git a/be/src/runtime/load_stream.cpp b/be/src/runtime/load_stream.cpp index daca91e978c837..9d1722c1726986 100644 --- a/be/src/runtime/load_stream.cpp +++ b/be/src/runtime/load_stream.cpp @@ -242,7 +242,7 @@ LoadStream::~LoadStream() { LOG(INFO) << "load stream is deconstructed " << *this; } -Status LoadStream::init(const POpenStreamSinkRequest* request) { +Status LoadStream::init(const POpenLoadStreamRequest* request) { _txn_id = request->txn_id(); _schema = std::make_shared(); diff --git a/be/src/runtime/load_stream.h b/be/src/runtime/load_stream.h index 317dc51086178b..fe7d90d502ec60 100644 --- a/be/src/runtime/load_stream.h +++ b/be/src/runtime/load_stream.h @@ -106,7 +106,7 @@ class LoadStream : public brpc::StreamInputHandler { LoadStream(PUniqueId load_id, LoadStreamMgr* load_stream_mgr, bool enable_profile); ~LoadStream(); - Status init(const POpenStreamSinkRequest* request); + Status init(const POpenLoadStreamRequest* request); void add_source(int64_t src_id) { std::lock_guard lock_guard(_lock); diff --git a/be/src/runtime/load_stream_mgr.cpp b/be/src/runtime/load_stream_mgr.cpp index d1af7b60d3fd3d..b3553046aec9f8 100644 --- a/be/src/runtime/load_stream_mgr.cpp +++ b/be/src/runtime/load_stream_mgr.cpp @@ -45,7 +45,7 @@ LoadStreamMgr::~LoadStreamMgr() { _file_writer_thread_pool->shutdown(); } -Status LoadStreamMgr::open_load_stream(const POpenStreamSinkRequest* request, +Status LoadStreamMgr::open_load_stream(const POpenLoadStreamRequest* request, LoadStreamSharedPtr& load_stream) { UniqueId load_id(request->load_id()); diff --git a/be/src/runtime/load_stream_mgr.h b/be/src/runtime/load_stream_mgr.h index da3ae98a42e56f..30d4ed069c485e 100644 --- a/be/src/runtime/load_stream_mgr.h +++ b/be/src/runtime/load_stream_mgr.h @@ -39,7 +39,7 @@ class LoadStreamMgr { FifoThreadPool* light_work_pool); ~LoadStreamMgr(); - Status open_load_stream(const POpenStreamSinkRequest* request, + Status open_load_stream(const POpenLoadStreamRequest* request, LoadStreamSharedPtr& load_stream); void clear_load(UniqueId loadid); std::unique_ptr new_token() { diff --git a/be/src/service/internal_service.cpp b/be/src/service/internal_service.cpp index cfaef4895b3eb5..dba01f1b6685c1 100644 --- a/be/src/service/internal_service.cpp +++ b/be/src/service/internal_service.cpp @@ -355,8 +355,8 @@ void PInternalServiceImpl::exec_plan_fragment_start(google::protobuf::RpcControl } void PInternalServiceImpl::open_load_stream(google::protobuf::RpcController* controller, - const POpenStreamSinkRequest* request, - POpenStreamSinkResponse* response, + const POpenLoadStreamRequest* request, + POpenLoadStreamResponse* response, google::protobuf::Closure* done) { bool ret = _light_work_pool.try_offer([this, controller, request, response, done]() { signal::set_signal_task_id(request->load_id()); diff --git a/be/src/service/internal_service.h b/be/src/service/internal_service.h index 3ef14b6c265674..ca28c8b8b06c52 100644 --- a/be/src/service/internal_service.h +++ b/be/src/service/internal_service.h @@ -94,7 +94,7 @@ class PInternalServiceImpl : public PBackendService { google::protobuf::Closure* done) override; void open_load_stream(google::protobuf::RpcController* controller, - const POpenStreamSinkRequest* request, POpenStreamSinkResponse* response, + const POpenLoadStreamRequest* request, POpenLoadStreamResponse* response, google::protobuf::Closure* done) override; void tablet_writer_add_block(google::protobuf::RpcController* controller, diff --git a/be/src/vec/sink/load_stream_stub.cpp b/be/src/vec/sink/load_stream_stub.cpp index 60ef352ddbb7c0..a953747f27b014 100644 --- a/be/src/vec/sink/load_stream_stub.cpp +++ b/be/src/vec/sink/load_stream_stub.cpp @@ -125,7 +125,7 @@ Status LoadStreamStub::open(BrpcClientCache* client_cache, return Status::Error(ret, "Failed to create stream"); } cntl.set_timeout_ms(config::open_load_stream_timeout_ms); - POpenStreamSinkRequest request; + POpenLoadStreamRequest request; *request.mutable_load_id() = _load_id; request.set_src_id(_src_id); request.set_txn_id(txn_id); @@ -134,7 +134,7 @@ Status LoadStreamStub::open(BrpcClientCache* client_cache, for (auto& tablet : tablets_for_schema) { *request.add_tablets() = tablet; } - POpenStreamSinkResponse response; + POpenLoadStreamResponse response; // use "pooled" connection to avoid conflicts between streaming rpc and regular rpc, // see: https://github.com/apache/brpc/issues/392 const auto& stub = client_cache->get_new_client_no_cache(host_port, "baidu_std", "pooled"); diff --git a/be/test/runtime/load_stream_test.cpp b/be/test/runtime/load_stream_test.cpp index 17c8b3707ae552..bdd0ace9a8b97c 100644 --- a/be/test/runtime/load_stream_test.cpp +++ b/be/test/runtime/load_stream_test.cpp @@ -348,8 +348,8 @@ class LoadStreamMgrTest : public testing::Test { : _sd(brpc::INVALID_STREAM_ID), _load_stream_mgr(load_stream_mgr) {} virtual ~StreamService() { brpc::StreamClose(_sd); }; virtual void open_load_stream(google::protobuf::RpcController* controller, - const POpenStreamSinkRequest* request, - POpenStreamSinkResponse* response, + const POpenLoadStreamRequest* request, + POpenLoadStreamResponse* response, google::protobuf::Closure* done) { brpc::ClosureGuard done_guard(done); std::unique_ptr status = std::make_unique(); @@ -438,8 +438,8 @@ class LoadStreamMgrTest : public testing::Test { return Status::InternalError("Fail to create stream"); } - POpenStreamSinkRequest request; - POpenStreamSinkResponse response; + POpenLoadStreamRequest request; + POpenLoadStreamResponse response; PUniqueId id; id.set_hi(1); id.set_lo(1); diff --git a/gensrc/proto/internal_service.proto b/gensrc/proto/internal_service.proto index 99f4464fd5957b..9a36916317f70d 100644 --- a/gensrc/proto/internal_service.proto +++ b/gensrc/proto/internal_service.proto @@ -742,7 +742,7 @@ message PGroupCommitInsertResponse { optional int64 filtered_rows = 5; } -message POpenStreamSinkRequest { +message POpenLoadStreamRequest { optional PUniqueId load_id = 1; optional int64 txn_id = 2; optional int64 src_id = 3; @@ -757,7 +757,7 @@ message PTabletSchemaWithIndex { optional bool enable_unique_key_merge_on_write = 3; } -message POpenStreamSinkResponse { +message POpenLoadStreamResponse { optional PStatus status = 1; repeated PTabletSchemaWithIndex tablet_schemas = 2; } @@ -798,7 +798,7 @@ service PBackendService { rpc cancel_plan_fragment(PCancelPlanFragmentRequest) returns (PCancelPlanFragmentResult); rpc fetch_data(PFetchDataRequest) returns (PFetchDataResult); rpc tablet_writer_open(PTabletWriterOpenRequest) returns (PTabletWriterOpenResult); - rpc open_load_stream(POpenStreamSinkRequest) returns (POpenStreamSinkResponse); + rpc open_load_stream(POpenLoadStreamRequest) returns (POpenLoadStreamResponse); rpc tablet_writer_add_block(PTabletWriterAddBlockRequest) returns (PTabletWriterAddBlockResult); rpc tablet_writer_add_block_by_http(PEmptyRequest) returns (PTabletWriterAddBlockResult); rpc tablet_writer_cancel(PTabletWriterCancelRequest) returns (PTabletWriterCancelResult); From 4995ca8fba6a768ab5eb718a68e324d94c82c497 Mon Sep 17 00:00:00 2001 From: Kaijie Chen Date: Tue, 7 Nov 2023 22:42:16 +0800 Subject: [PATCH 19/88] [fix](move-memtable) ensure segment is flushed before add segment (#26522) --- be/src/olap/rowset/beta_rowset_writer.cpp | 2 +- be/src/olap/rowset/beta_rowset_writer.h | 2 +- be/src/olap/rowset/beta_rowset_writer_v2.cpp | 2 +- be/src/olap/rowset/beta_rowset_writer_v2.h | 2 +- be/src/olap/rowset/rowset_writer.h | 4 ++-- be/src/runtime/load_stream.cpp | 11 +++++++++-- be/src/runtime/load_stream_writer.cpp | 16 ++++++++++++---- be/src/runtime/load_stream_writer.h | 2 +- be/src/vec/sink/load_stream_stub.cpp | 2 +- be/src/vec/sink/load_stream_stub.h | 2 +- 10 files changed, 30 insertions(+), 15 deletions(-) diff --git a/be/src/olap/rowset/beta_rowset_writer.cpp b/be/src/olap/rowset/beta_rowset_writer.cpp index 5ef14743492b95..080086a0a93b4c 100644 --- a/be/src/olap/rowset/beta_rowset_writer.cpp +++ b/be/src/olap/rowset/beta_rowset_writer.cpp @@ -691,7 +691,7 @@ Status BetaRowsetWriter::_check_segment_number_limit() { return Status::OK(); } -Status BetaRowsetWriter::add_segment(uint32_t segment_id, SegmentStatistics& segstat) { +Status BetaRowsetWriter::add_segment(uint32_t segment_id, const SegmentStatistics& segstat) { uint32_t segid_offset = segment_id - _segment_start_id; { std::lock_guard lock(_segid_statistics_map_mutex); diff --git a/be/src/olap/rowset/beta_rowset_writer.h b/be/src/olap/rowset/beta_rowset_writer.h index 9c615048a7fdc2..8918e30f3e2438 100644 --- a/be/src/olap/rowset/beta_rowset_writer.h +++ b/be/src/olap/rowset/beta_rowset_writer.h @@ -78,7 +78,7 @@ class BetaRowsetWriter : public RowsetWriter { Status create_file_writer(uint32_t segment_id, io::FileWriterPtr& writer) override; - Status add_segment(uint32_t segment_id, SegmentStatistics& segstat) override; + Status add_segment(uint32_t segment_id, const SegmentStatistics& segstat) override; Status flush() override; diff --git a/be/src/olap/rowset/beta_rowset_writer_v2.cpp b/be/src/olap/rowset/beta_rowset_writer_v2.cpp index abd7af2aabaf6b..e16ce5fa9fa0a8 100644 --- a/be/src/olap/rowset/beta_rowset_writer_v2.cpp +++ b/be/src/olap/rowset/beta_rowset_writer_v2.cpp @@ -88,7 +88,7 @@ Status BetaRowsetWriterV2::create_file_writer(uint32_t segment_id, io::FileWrite return Status::OK(); } -Status BetaRowsetWriterV2::add_segment(uint32_t segment_id, SegmentStatistics& segstat) { +Status BetaRowsetWriterV2::add_segment(uint32_t segment_id, const SegmentStatistics& segstat) { for (const auto& stream : _streams) { RETURN_IF_ERROR(stream->add_segment(_context.partition_id, _context.index_id, _context.tablet_id, segment_id, segstat)); diff --git a/be/src/olap/rowset/beta_rowset_writer_v2.h b/be/src/olap/rowset/beta_rowset_writer_v2.h index d35f4b2486f31a..1a6db6df4092f7 100644 --- a/be/src/olap/rowset/beta_rowset_writer_v2.h +++ b/be/src/olap/rowset/beta_rowset_writer_v2.h @@ -120,7 +120,7 @@ class BetaRowsetWriterV2 : public RowsetWriter { return Status::OK(); } - Status add_segment(uint32_t segment_id, SegmentStatistics& segstat) override; + Status add_segment(uint32_t segment_id, const SegmentStatistics& segstat) override; int32_t allocate_segment_id() override { return _next_segment_id.fetch_add(1); }; diff --git a/be/src/olap/rowset/rowset_writer.h b/be/src/olap/rowset/rowset_writer.h index 7958cc2ce0727a..8ba5666bf56f93 100644 --- a/be/src/olap/rowset/rowset_writer.h +++ b/be/src/olap/rowset/rowset_writer.h @@ -48,7 +48,7 @@ struct SegmentStatistics { index_size(pb.index_size()), key_bounds(pb.key_bounds()) {} - void to_pb(SegmentStatisticsPB* segstat_pb) { + void to_pb(SegmentStatisticsPB* segstat_pb) const { segstat_pb->set_row_num(row_num); segstat_pb->set_data_size(data_size); segstat_pb->set_index_size(index_size); @@ -114,7 +114,7 @@ class RowsetWriter { "RowsetWriter not support flush_single_block"); } - virtual Status add_segment(uint32_t segment_id, SegmentStatistics& segstat) { + virtual Status add_segment(uint32_t segment_id, const SegmentStatistics& segstat) { return Status::NotSupported("RowsetWriter does not support add_segment"); } diff --git a/be/src/runtime/load_stream.cpp b/be/src/runtime/load_stream.cpp index 9d1722c1726986..b9cc5891b489c4 100644 --- a/be/src/runtime/load_stream.cpp +++ b/be/src/runtime/load_stream.cpp @@ -129,7 +129,7 @@ Status TabletStream::append_data(const PStreamHeader& header, butil::IOBuf* data LOG(INFO) << "write data failed " << *this; } }; - return _flush_tokens[segid % _flush_tokens.size()]->submit_func(flush_func); + return _flush_tokens[new_segid % _flush_tokens.size()]->submit_func(flush_func); } Status TabletStream::add_segment(const PStreamHeader& header, butil::IOBuf* data) { @@ -151,7 +151,14 @@ Status TabletStream::add_segment(const PStreamHeader& header, butil::IOBuf* data } DCHECK(new_segid != std::numeric_limits::max()); - return _load_stream_writer->add_segment(new_segid, stat); + auto add_segment_func = [this, new_segid, stat]() { + auto st = _load_stream_writer->add_segment(new_segid, stat); + if (!st.ok() && _failed_st->ok()) { + _failed_st = std::make_shared(st); + LOG(INFO) << "add segment failed " << *this; + } + }; + return _flush_tokens[new_segid % _flush_tokens.size()]->submit_func(add_segment_func); } Status TabletStream::close() { diff --git a/be/src/runtime/load_stream_writer.cpp b/be/src/runtime/load_stream_writer.cpp index e44a682b25babd..504e02fb3b1600 100644 --- a/be/src/runtime/load_stream_writer.cpp +++ b/be/src/runtime/load_stream_writer.cpp @@ -121,7 +121,15 @@ Status LoadStreamWriter::close_segment(uint32_t segid) { return Status::OK(); } -Status LoadStreamWriter::add_segment(uint32_t segid, SegmentStatistics& stat) { +Status LoadStreamWriter::add_segment(uint32_t segid, const SegmentStatistics& stat) { + if (_segment_file_writers[segid]->bytes_appended() != stat.data_size) { + LOG(WARNING) << _segment_file_writers[segid]->path() << " is incomplete, actual size: " + << _segment_file_writers[segid]->bytes_appended() + << ", expected size: " << stat.data_size; + return Status::Corruption("segment {} is incomplete, actual size: {}, expected size: {}", + _segment_file_writers[segid]->path().native(), + _segment_file_writers[segid]->bytes_appended(), stat.data_size); + } return _rowset_writer->add_segment(segid, stat); } @@ -143,9 +151,9 @@ Status LoadStreamWriter::close() { return Status::Error("flush segment failed"); } - for (size_t i = 0; i < _segment_file_writers.size(); i++) { - if (!_segment_file_writers[i]->is_closed()) { - return Status::Corruption("segment {} is not eos", i); + for (const auto& writer : _segment_file_writers) { + if (!writer->is_closed()) { + return Status::Corruption("segment {} is not closed", writer->path().native()); } } diff --git a/be/src/runtime/load_stream_writer.h b/be/src/runtime/load_stream_writer.h index e4a3341cea38d7..dc952d2c18da48 100644 --- a/be/src/runtime/load_stream_writer.h +++ b/be/src/runtime/load_stream_writer.h @@ -71,7 +71,7 @@ class LoadStreamWriter { Status close_segment(uint32_t segid); - Status add_segment(uint32_t segid, SegmentStatistics& stat); + Status add_segment(uint32_t segid, const SegmentStatistics& stat); // wait for all memtables to be flushed. Status close(); diff --git a/be/src/vec/sink/load_stream_stub.cpp b/be/src/vec/sink/load_stream_stub.cpp index a953747f27b014..fe9887b3a3e00f 100644 --- a/be/src/vec/sink/load_stream_stub.cpp +++ b/be/src/vec/sink/load_stream_stub.cpp @@ -174,7 +174,7 @@ Status LoadStreamStub::append_data(int64_t partition_id, int64_t index_id, int64 // ADD_SEGMENT Status LoadStreamStub::add_segment(int64_t partition_id, int64_t index_id, int64_t tablet_id, - int64_t segment_id, SegmentStatistics& segment_stat) { + int64_t segment_id, const SegmentStatistics& segment_stat) { PStreamHeader header; header.set_src_id(_src_id); *header.mutable_load_id() = _load_id; diff --git a/be/src/vec/sink/load_stream_stub.h b/be/src/vec/sink/load_stream_stub.h index 60a48427618306..2db9ffcd95057f 100644 --- a/be/src/vec/sink/load_stream_stub.h +++ b/be/src/vec/sink/load_stream_stub.h @@ -161,7 +161,7 @@ class LoadStreamStub { // ADD_SEGMENT Status add_segment(int64_t partition_id, int64_t index_id, int64_t tablet_id, - int64_t segment_id, SegmentStatistics& segment_stat); + int64_t segment_id, const SegmentStatistics& segment_stat); // CLOSE_LOAD Status close_load(const std::vector& tablets_to_commit); From a6756b46609e7a96bebce26658379f0516ea21d4 Mon Sep 17 00:00:00 2001 From: Gabriel Date: Wed, 8 Nov 2023 00:14:48 +0800 Subject: [PATCH 20/88] [pipelineX](bug) Fix broadcast buffer reference count (#26545) --- be/src/pipeline/exec/exchange_sink_buffer.cpp | 9 +++----- be/src/pipeline/exec/exchange_sink_buffer.h | 7 ++++--- .../pipeline/exec/exchange_sink_operator.cpp | 21 +++++++------------ .../exec/result_file_sink_operator.cpp | 2 +- be/src/vec/sink/vdata_stream_sender.cpp | 6 +++++- be/src/vec/sink/vdata_stream_sender.h | 9 ++++---- 6 files changed, 25 insertions(+), 29 deletions(-) diff --git a/be/src/pipeline/exec/exchange_sink_buffer.cpp b/be/src/pipeline/exec/exchange_sink_buffer.cpp index 577eb4a46224fe..f450fa69605fd4 100644 --- a/be/src/pipeline/exec/exchange_sink_buffer.cpp +++ b/be/src/pipeline/exec/exchange_sink_buffer.cpp @@ -177,20 +177,17 @@ Status ExchangeSinkBuffer::add_block(TransmitInfo&& request) { } template -Status ExchangeSinkBuffer::add_block(BroadcastTransmitInfo&& request, - [[maybe_unused]] bool* sent) { +Status ExchangeSinkBuffer::add_block(BroadcastTransmitInfo&& request) { if (_is_finishing) { + request.block_holder->unref(); return Status::OK(); } TUniqueId ins_id = request.channel->_fragment_instance_id; if (_is_receiver_eof(ins_id.lo)) { + request.block_holder->unref(); return Status::EndOfFile("receiver eof"); } bool send_now = false; - if (sent) { - *sent = true; - } - request.block_holder->ref(); { std::unique_lock lock(*_instance_to_package_queue_mutex[ins_id.lo]); // Do not have in process rpc, directly send diff --git a/be/src/pipeline/exec/exchange_sink_buffer.h b/be/src/pipeline/exec/exchange_sink_buffer.h index d63dd2a55f9bdb..2b30f6fac70a63 100644 --- a/be/src/pipeline/exec/exchange_sink_buffer.h +++ b/be/src/pipeline/exec/exchange_sink_buffer.h @@ -76,15 +76,16 @@ class BroadcastPBlockHolder { BroadcastPBlockHolder(pipeline::BroadcastDependency* dep) : _ref_count(0), _dep(dep) {} ~BroadcastPBlockHolder() noexcept = default; + void ref(int delta) noexcept { _ref_count._value.fetch_add(delta); } void unref() noexcept; - void ref() noexcept { _ref_count._value.fetch_add(1); } + void ref() noexcept { ref(1); } bool available() { return _ref_count._value == 0; } PBlock* get_block() { return &pblock; } private: - AtomicWrapper _ref_count; + AtomicWrapper _ref_count; PBlock pblock; pipeline::BroadcastDependency* _dep; }; @@ -177,7 +178,7 @@ class ExchangeSinkBuffer { void register_sink(TUniqueId); Status add_block(TransmitInfo&& request); - Status add_block(BroadcastTransmitInfo&& request, [[maybe_unused]] bool* sent); + Status add_block(BroadcastTransmitInfo&& request); bool can_write() const; bool is_pending_finish(); void close(); diff --git a/be/src/pipeline/exec/exchange_sink_operator.cpp b/be/src/pipeline/exec/exchange_sink_operator.cpp index e6bcccbabb2d7b..44d6b6448ed368 100644 --- a/be/src/pipeline/exec/exchange_sink_operator.cpp +++ b/be/src/pipeline/exec/exchange_sink_operator.cpp @@ -344,30 +344,25 @@ Status ExchangeSinkOperatorX::sink(RuntimeState* state, vectorized::Block* block } else { block_holder->get_block()->Clear(); } - Status error_status = Status::OK(); - bool sent = false; + local_state._broadcast_dependency->take_available_block(); + block_holder->ref(local_state.channels.size()); + Status status; for (auto channel : local_state.channels) { if (!channel->is_receiver_eof()) { Status status; if (channel->is_local()) { + block_holder->unref(); status = channel->send_local_block(&cur_block); } else { SCOPED_CONSUME_MEM_TRACKER(_mem_tracker.get()); status = channel->send_broadcast_block( - block_holder, &sent, source_state == SourceState::FINISHED); - } - if (status.is()) { - _handle_eof_channel(state, channel, status); - } else if (!status.ok()) { - error_status = status; - break; + block_holder, source_state == SourceState::FINISHED); } + HANDLE_CHANNEL_STATUS(state, channel, status); + } else { + block_holder->unref(); } } - if (sent) { - local_state._broadcast_dependency->take_available_block(); - } - RETURN_IF_ERROR(error_status); cur_block.clear_column_data(); local_state._serializer.get_block()->set_muatable_columns( cur_block.mutate_columns()); diff --git a/be/src/pipeline/exec/result_file_sink_operator.cpp b/be/src/pipeline/exec/result_file_sink_operator.cpp index 217696c693904f..3193c1b07c4921 100644 --- a/be/src/pipeline/exec/result_file_sink_operator.cpp +++ b/be/src/pipeline/exec/result_file_sink_operator.cpp @@ -241,7 +241,7 @@ Status ResultFileSinkLocalState::close(RuntimeState* state, Status exec_status) } else { SCOPED_CONSUME_MEM_TRACKER(_mem_tracker.get()); status = channel->send_broadcast_block(_block_holder.get(), - nullptr, true); + true); } HANDLE_CHANNEL_STATUS(state, channel, status); } diff --git a/be/src/vec/sink/vdata_stream_sender.cpp b/be/src/vec/sink/vdata_stream_sender.cpp index a7066f981ba988..728bd0c56f46f2 100644 --- a/be/src/vec/sink/vdata_stream_sender.cpp +++ b/be/src/vec/sink/vdata_stream_sender.cpp @@ -562,15 +562,19 @@ Status VDataStreamSender::send(RuntimeState* state, Block* block, bool eos) { block_holder->get_block()->Clear(); } Status status; + block_holder->ref(_channels.size()); for (auto channel : _channels) { if (!channel->is_receiver_eof()) { if (channel->is_local()) { + block_holder->unref(); status = channel->send_local_block(&cur_block); } else { SCOPED_CONSUME_MEM_TRACKER(_mem_tracker.get()); - status = channel->send_broadcast_block(block_holder, nullptr, eos); + status = channel->send_broadcast_block(block_holder, eos); } HANDLE_CHANNEL_STATUS(state, channel, status); + } else { + block_holder->unref(); } } cur_block.clear_column_data(); diff --git a/be/src/vec/sink/vdata_stream_sender.h b/be/src/vec/sink/vdata_stream_sender.h index 30a55f13296543..10116be03346ae 100644 --- a/be/src/vec/sink/vdata_stream_sender.h +++ b/be/src/vec/sink/vdata_stream_sender.h @@ -278,8 +278,7 @@ class Channel { virtual Status send_remote_block(PBlock* block, bool eos = false, Status exec_status = Status::OK()); - virtual Status send_broadcast_block(BroadcastPBlockHolder* block, [[maybe_unused]] bool* sent, - bool eos = false) { + virtual Status send_broadcast_block(BroadcastPBlockHolder* block, bool eos = false) { return Status::InternalError("Send BroadcastPBlockHolder is not allowed!"); } @@ -494,17 +493,17 @@ class PipChannel final : public Channel { return Status::OK(); } - Status send_broadcast_block(BroadcastPBlockHolder* block, [[maybe_unused]] bool* sent, - bool eos = false) override { + Status send_broadcast_block(BroadcastPBlockHolder* block, bool eos = false) override { COUNTER_UPDATE(Channel::_parent->blocks_sent_counter(), 1); if (eos) { if (_eos_send) { + block->unref(); return Status::OK(); } _eos_send = true; } if (eos || block->get_block()->column_metas_size()) { - RETURN_IF_ERROR(_buffer->add_block({this, block, eos}, sent)); + RETURN_IF_ERROR(_buffer->add_block({this, block, eos})); } return Status::OK(); } From 70bc8600a9e76e53b258dd08611309e4a04cfa6f Mon Sep 17 00:00:00 2001 From: TengJianPing <18241664+jacktengg@users.noreply.github.com> Date: Wed, 8 Nov 2023 09:05:58 +0800 Subject: [PATCH 21/88] [fix](regression) fix regression framework bug: if real test result is negative, it will miss check test result (#25734) --- be/src/vec/functions/function_binary_arithmetic.h | 3 ++- .../decimalv3/test_agg_keys_schema_change_decimalv3.out | 2 +- .../groovy/org/apache/doris/regression/util/OutputUtils.groovy | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/be/src/vec/functions/function_binary_arithmetic.h b/be/src/vec/functions/function_binary_arithmetic.h index 7198a08bb222ec..911704718fb1e6 100644 --- a/be/src/vec/functions/function_binary_arithmetic.h +++ b/be/src/vec/functions/function_binary_arithmetic.h @@ -79,7 +79,8 @@ struct OperationTraits { std::is_same_v>; static constexpr bool can_overflow = (is_plus_minus || is_multiply) && - (IsDecimalV2 || IsDecimalV2 || IsDecimal256 || IsDecimal256); + (IsDecimalV2 || IsDecimalV2 || IsDecimal128I || IsDecimal128I || + IsDecimal256 || IsDecimal256); static constexpr bool has_variadic_argument = !std::is_void_v()))>; }; diff --git a/regression-test/data/schema_change_p0/decimalv3/test_agg_keys_schema_change_decimalv3.out b/regression-test/data/schema_change_p0/decimalv3/test_agg_keys_schema_change_decimalv3.out index 1b9f52fd5ea3bb..fc5d8e286ce89b 100644 --- a/regression-test/data/schema_change_p0/decimalv3/test_agg_keys_schema_change_decimalv3.out +++ b/regression-test/data/schema_change_p0/decimalv3/test_agg_keys_schema_change_decimalv3.out @@ -18,7 +18,7 @@ 0.11111111111111111111111111111111100000 11111111111111111111111111111.1100000000 0.11111111111111111111111111111111100000 11111111111111111111111111111.110 -- !sql -- -0.11111111111111111111111111111111100000 9223372036854775.807 0.11111111111111111111111111111111100000 11111111111111111111111111111.110 +0.11111111111111111111111111111111100000 -999999999999999.999 0.11111111111111111111111111111111100000 11111111111111111111111111111.110 -- !sql -- 0.11111111111111111111111111111111100000 -9223.372036854775808 0.11111111111111111111111111111111100000 11111111111111111111111111111.110 diff --git a/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/OutputUtils.groovy b/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/OutputUtils.groovy index 757a4a593f8cc2..b140673e7a762e 100644 --- a/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/OutputUtils.groovy +++ b/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/OutputUtils.groovy @@ -76,7 +76,7 @@ class OutputUtils { double expectDouble = Double.parseDouble(expectCell) double realDouble = Double.parseDouble(realCell) - double realRelativeError = Math.abs(expectDouble - realDouble) / realDouble + double realRelativeError = Math.abs(expectDouble - realDouble) / Math.abs(realDouble) double expectRelativeError = 1e-8 if (expectRelativeError < realRelativeError) { From a354f87d2e038cf5b2c5be5bd9911101979f5d9a Mon Sep 17 00:00:00 2001 From: Gabriel Date: Wed, 8 Nov 2023 09:57:09 +0800 Subject: [PATCH 22/88] [refactor](pipeline) simplify runtime state ctor (#26461) --- be/src/pipeline/pipeline_fragment_context.cpp | 9 ++++++--- .../pipeline_x_fragment_context.cpp | 9 ++++++--- be/src/runtime/runtime_state.cpp | 20 +++++++++---------- be/src/runtime/runtime_state.h | 8 +++++--- be/src/vec/exec/vexchange_node.cpp | 2 ++ 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/be/src/pipeline/pipeline_fragment_context.cpp b/be/src/pipeline/pipeline_fragment_context.cpp index 4616ff2fb49995..67d0e6045b82be 100644 --- a/be/src/pipeline/pipeline_fragment_context.cpp +++ b/be/src/pipeline/pipeline_fragment_context.cpp @@ -221,9 +221,12 @@ Status PipelineFragmentContext::prepare(const doris::TPipelineFragmentParams& re local_params.backend_num); // 1. init _runtime_state - _runtime_state = RuntimeState::create_unique(local_params, request.query_id, - request.fragment_id, request.query_options, - _query_ctx->query_globals, _exec_env); + _runtime_state = RuntimeState::create_unique( + local_params.fragment_instance_id, request.query_id, request.fragment_id, + request.query_options, _query_ctx->query_globals, _exec_env); + if (local_params.__isset.runtime_filter_params) { + _runtime_state->set_runtime_filter_params(local_params.runtime_filter_params); + } _runtime_state->set_query_ctx(_query_ctx.get()); _runtime_state->set_query_mem_tracker(_query_ctx->query_mem_tracker); _runtime_state->set_tracer(std::move(tracer)); diff --git a/be/src/pipeline/pipeline_x/pipeline_x_fragment_context.cpp b/be/src/pipeline/pipeline_x/pipeline_x_fragment_context.cpp index 06659eb23e04ec..95cdf47bec5424 100644 --- a/be/src/pipeline/pipeline_x/pipeline_x_fragment_context.cpp +++ b/be/src/pipeline/pipeline_x/pipeline_x_fragment_context.cpp @@ -390,9 +390,12 @@ Status PipelineXFragmentContext::_build_pipeline_tasks( for (size_t i = 0; i < target_size; i++) { const auto& local_params = request.local_params[i]; - _runtime_states[i] = RuntimeState::create_unique(local_params, request.query_id, - request.fragment_id, request.query_options, - _query_ctx->query_globals, _exec_env); + _runtime_states[i] = RuntimeState::create_unique( + local_params.fragment_instance_id, request.query_id, request.fragment_id, + request.query_options, _query_ctx->query_globals, _exec_env); + if (local_params.__isset.runtime_filter_params) { + _runtime_states[i]->set_runtime_filter_params(local_params.runtime_filter_params); + } _runtime_states[i]->set_query_ctx(_query_ctx.get()); _runtime_states[i]->set_query_mem_tracker(_query_ctx->query_mem_tracker); _runtime_states[i]->set_tracer(_runtime_state->get_tracer()); diff --git a/be/src/runtime/runtime_state.cpp b/be/src/runtime/runtime_state.cpp index 7a24b86621bbfb..84329be07055f1 100644 --- a/be/src/runtime/runtime_state.cpp +++ b/be/src/runtime/runtime_state.cpp @@ -101,11 +101,10 @@ RuntimeState::RuntimeState(const TPlanFragmentExecParams& fragment_exec_params, DCHECK(status.ok()); } -RuntimeState::RuntimeState(const TPipelineInstanceParams& pipeline_params, - const TUniqueId& query_id, int32_t fragment_id, - const TQueryOptions& query_options, const TQueryGlobals& query_globals, - ExecEnv* exec_env) - : _profile("Fragment " + print_id(pipeline_params.fragment_instance_id)), +RuntimeState::RuntimeState(const TUniqueId& instance_id, const TUniqueId& query_id, + int32_t fragment_id, const TQueryOptions& query_options, + const TQueryGlobals& query_globals, ExecEnv* exec_env) + : _profile("Fragment " + print_id(instance_id)), _load_channel_profile(""), _obj_pool(new ObjectPool()), _runtime_filter_mgr(new RuntimeFilterMgr(query_id, this)), @@ -125,11 +124,7 @@ RuntimeState::RuntimeState(const TPipelineInstanceParams& pipeline_params, _normal_row_number(0), _error_row_number(0), _error_log_file(nullptr) { - if (pipeline_params.__isset.runtime_filter_params) { - _runtime_filter_mgr->set_runtime_filter_params(pipeline_params.runtime_filter_params); - } - Status status = - init(pipeline_params.fragment_instance_id, query_options, query_globals, exec_env); + [[maybe_unused]] auto status = init(instance_id, query_options, query_globals, exec_env); DCHECK(status.ok()); } @@ -273,6 +268,11 @@ Status RuntimeState::init(const TUniqueId& fragment_instance_id, const TQueryOpt return Status::OK(); } +void RuntimeState::set_runtime_filter_params( + const TRuntimeFilterParams& runtime_filter_params) const { + _runtime_filter_mgr->set_runtime_filter_params(runtime_filter_params); +} + void RuntimeState::init_mem_trackers(const TUniqueId& id, const std::string& name) { _query_mem_tracker = std::make_shared( MemTrackerLimiter::Type::EXPERIMENTAL, fmt::format("{}#Id={}", name, print_id(id))); diff --git a/be/src/runtime/runtime_state.h b/be/src/runtime/runtime_state.h index 805951e34e3b56..cba5142c154a1b 100644 --- a/be/src/runtime/runtime_state.h +++ b/be/src/runtime/runtime_state.h @@ -72,9 +72,9 @@ class RuntimeState { const TQueryOptions& query_options, const TQueryGlobals& query_globals, ExecEnv* exec_env); - RuntimeState(const TPipelineInstanceParams& pipeline_params, const TUniqueId& query_id, - int32 fragment_id, const TQueryOptions& query_options, - const TQueryGlobals& query_globals, ExecEnv* exec_env); + RuntimeState(const TUniqueId& instance_id, const TUniqueId& query_id, int32 fragment_id, + const TQueryOptions& query_options, const TQueryGlobals& query_globals, + ExecEnv* exec_env); // Used by pipelineX. This runtime state is only used for setup. RuntimeState(const TUniqueId& query_id, int32 fragment_id, const TQueryOptions& query_options, @@ -93,6 +93,8 @@ class RuntimeState { Status init(const TUniqueId& fragment_instance_id, const TQueryOptions& query_options, const TQueryGlobals& query_globals, ExecEnv* exec_env); + void set_runtime_filter_params(const TRuntimeFilterParams& runtime_filter_params) const; + // for ut and non-query. void set_exec_env(ExecEnv* exec_env) { _exec_env = exec_env; } void init_mem_trackers(const TUniqueId& id = TUniqueId(), const std::string& name = "unknown"); diff --git a/be/src/vec/exec/vexchange_node.cpp b/be/src/vec/exec/vexchange_node.cpp index 4b2e4f76d03e77..eadc4fee059ca4 100644 --- a/be/src/vec/exec/vexchange_node.cpp +++ b/be/src/vec/exec/vexchange_node.cpp @@ -66,6 +66,8 @@ Status VExchangeNode::prepare(RuntimeState* state) { SCOPED_TIMER(_exec_timer); DCHECK_GT(_num_senders, 0); _sub_plan_query_statistics_recvr.reset(new QueryStatisticsRecvr()); + CHECK(state->exec_env() != nullptr); + CHECK(state->exec_env()->vstream_mgr() != nullptr); _stream_recvr = state->exec_env()->vstream_mgr()->create_recvr( state, _input_row_desc, state->fragment_instance_id(), _id, _num_senders, _runtime_profile.get(), _is_merging, _sub_plan_query_statistics_recvr); From 607a5d25f183f85bc68b5438f3612d76bdfe959d Mon Sep 17 00:00:00 2001 From: HHoflittlefish777 <77738092+HHoflittlefish777@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:07:05 +0800 Subject: [PATCH 23/88] [feature](streamload) support HTTP request with chunked transfer (#26520) --- be/src/http/action/stream_load.cpp | 21 +++++++++++-- be/src/io/fs/stream_load_pipe.cpp | 2 +- .../runtime/stream_load/stream_load_context.h | 1 + .../stream_load/test_chunked_transfer.csv | 2 ++ .../load_p0/stream_load/test_stream_load.out | 4 +++ .../stream_load/test_stream_load.groovy | 30 +++++++++++++++++++ 6 files changed, 56 insertions(+), 4 deletions(-) create mode 100644 regression-test/data/load_p0/stream_load/test_chunked_transfer.csv diff --git a/be/src/http/action/stream_load.cpp b/be/src/http/action/stream_load.cpp index 99a98afbc37b8d..d16d41795a8a1b 100644 --- a/be/src/http/action/stream_load.cpp +++ b/be/src/http/action/stream_load.cpp @@ -76,6 +76,9 @@ DEFINE_COUNTER_METRIC_PROTOTYPE_2ARG(streaming_load_requests_total, MetricUnit:: DEFINE_COUNTER_METRIC_PROTOTYPE_2ARG(streaming_load_duration_ms, MetricUnit::MILLISECONDS); DEFINE_GAUGE_METRIC_PROTOTYPE_2ARG(streaming_load_current_processing, MetricUnit::REQUESTS); +static constexpr size_t MIN_CHUNK_SIZE = 64 * 1024; +static const string CHUNK = "chunked"; + #ifdef BE_TEST TStreamLoadPutResult k_stream_load_put_result; #endif @@ -292,6 +295,12 @@ Status StreamLoadAction::_on_header(HttpRequest* http_req, std::shared_ptrheader(HttpHeaders::TRANSFER_ENCODING).empty()) { + if (http_req->header(HttpHeaders::TRANSFER_ENCODING).find(CHUNK) != std::string::npos) { + ctx->is_chunked_transfer = true; + } + } + if (!http_req->header(HTTP_TIMEOUT).empty()) { try { ctx->timeout_second = std::stoi(http_req->header(HTTP_TIMEOUT)); @@ -369,9 +378,15 @@ Status StreamLoadAction::_process_put(HttpRequest* http_req, request.__set_header_type(ctx->header_type); request.__set_loadId(ctx->id.to_thrift()); if (ctx->use_streaming) { - auto pipe = std::make_shared( - io::kMaxPipeBufferedBytes /* max_buffered_bytes */, 64 * 1024 /* min_chunk_size */, - ctx->body_bytes /* total_length */); + std::shared_ptr pipe; + if (ctx->is_chunked_transfer) { + pipe = std::make_shared( + io::kMaxPipeBufferedBytes /* max_buffered_bytes */); + } else { + pipe = std::make_shared( + io::kMaxPipeBufferedBytes /* max_buffered_bytes */, + MIN_CHUNK_SIZE /* min_chunk_size */, ctx->body_bytes /* total_length */); + } request.fileType = TFileType::FILE_STREAM; ctx->body_sink = pipe; ctx->pipe = pipe; diff --git a/be/src/io/fs/stream_load_pipe.cpp b/be/src/io/fs/stream_load_pipe.cpp index 25be598e90eb23..00fa038f98ee94 100644 --- a/be/src/io/fs/stream_load_pipe.cpp +++ b/be/src/io/fs/stream_load_pipe.cpp @@ -90,7 +90,7 @@ Status StreamLoadPipe::read_at_impl(size_t /*offset*/, Slice result, size_t* byt return Status::OK(); } -// If _total_length == -1, this should be a Kafka routine load task, +// If _total_length == -1, this should be a Kafka routine load task or stream load with chunked transfer HTTP request, // just get the next buffer directly from the buffer queue, because one buffer contains a complete piece of data. // Otherwise, this should be a stream load task that needs to read the specified amount of data. Status StreamLoadPipe::read_one_message(std::unique_ptr* data, size_t* length) { diff --git a/be/src/runtime/stream_load/stream_load_context.h b/be/src/runtime/stream_load/stream_load_context.h index ffbed37fe3abf8..2b8d271157d107 100644 --- a/be/src/runtime/stream_load/stream_load_context.h +++ b/be/src/runtime/stream_load/stream_load_context.h @@ -161,6 +161,7 @@ class StreamLoadContext { // only used to check if we receive whole body size_t body_bytes = 0; size_t receive_bytes = 0; + bool is_chunked_transfer = false; int64_t txn_id = default_txn_id; diff --git a/regression-test/data/load_p0/stream_load/test_chunked_transfer.csv b/regression-test/data/load_p0/stream_load/test_chunked_transfer.csv new file mode 100644 index 00000000000000..26831f07e769c4 --- /dev/null +++ b/regression-test/data/load_p0/stream_load/test_chunked_transfer.csv @@ -0,0 +1,2 @@ +2|-50|1|44|1 +1|-50|1|2|1 diff --git a/regression-test/data/load_p0/stream_load/test_stream_load.out b/regression-test/data/load_p0/stream_load/test_stream_load.out index a1971041f0e674..8c88c4f5dc2615 100644 --- a/regression-test/data/load_p0/stream_load/test_stream_load.out +++ b/regression-test/data/load_p0/stream_load/test_stream_load.out @@ -113,3 +113,7 @@ 1 -50 1 2 1 \N 2 -50 1 44 1 \N +-- !sql_chunked_transfer -- +1 -50 1 2 1 \N +2 -50 1 44 1 \N + diff --git a/regression-test/suites/load_p0/stream_load/test_stream_load.groovy b/regression-test/suites/load_p0/stream_load/test_stream_load.groovy index f4ac161f5709df..8f4801e9cfe20d 100644 --- a/regression-test/suites/load_p0/stream_load/test_stream_load.groovy +++ b/regression-test/suites/load_p0/stream_load/test_stream_load.groovy @@ -1134,5 +1134,35 @@ suite("test_stream_load", "p0") { } finally { sql """ DROP TABLE IF EXISTS ${tableName15} FORCE""" } + + // test chunked transfer + def tableName16 = "test_chunked_transfer" + try { + sql """ DROP TABLE IF EXISTS ${tableName16} """ + sql """ + CREATE TABLE IF NOT EXISTS ${tableName16} ( + `k1` bigint(20) NULL DEFAULT "1", + `k2` bigint(20) NULL , + `v1` tinyint(4) NULL, + `v2` tinyint(4) NULL, + `v3` tinyint(4) NULL, + `v4` DATETIME NULL + ) ENGINE=OLAP + DISTRIBUTED BY HASH(`k1`) BUCKETS 3 + PROPERTIES ("replication_allocation" = "tag.location.default: 1"); + """ + + def command = "curl --location-trusted -u ${context.config.feHttpUser}:${context.config.feHttpPassword} -H column_separator:| -H Transfer-Encoding:chunked -H columns:k1,k2,v1,v2,v3 -T ${context.dataPath}/test_chunked_transfer.csv http://${context.config.feHttpAddress}/api/${db}/${tableName16}/_stream_load" + log.info("test chunked transfer command: ${command}") + def process = command.execute() + code = process.waitFor() + out = process.text + json2pc = parseJson(out) + log.info("test chunked transfer result: ${out}".toString()) + + qt_sql_chunked_transfer "select * from ${tableName16} order by k1" + } finally { + sql """ DROP TABLE IF EXISTS ${tableName16} FORCE""" + } } From 519b48648e0bd637267de0945268ed3766bb5732 Mon Sep 17 00:00:00 2001 From: Kaijie Chen Date: Wed, 8 Nov 2023 10:09:06 +0800 Subject: [PATCH 24/88] [fix](move-memtable) handle status when possible (#26526) --- be/src/olap/delta_writer_v2.cpp | 10 +++++----- be/src/olap/delta_writer_v2.h | 5 ++--- be/src/olap/rowset/beta_rowset_writer_v2.cpp | 2 +- be/src/vec/sink/delta_writer_v2_pool.cpp | 4 ++-- be/src/vec/sink/delta_writer_v2_pool.h | 3 ++- be/src/vec/sink/vtablet_sink_v2.cpp | 10 ++++------ be/test/vec/exec/delta_writer_v2_pool_test.cpp | 18 +++--------------- 7 files changed, 19 insertions(+), 33 deletions(-) diff --git a/be/src/olap/delta_writer_v2.cpp b/be/src/olap/delta_writer_v2.cpp index 8e13f8f3050c62..52e22d84b69475 100644 --- a/be/src/olap/delta_writer_v2.cpp +++ b/be/src/olap/delta_writer_v2.cpp @@ -64,11 +64,11 @@ namespace doris { using namespace ErrorCode; -Status DeltaWriterV2::open(WriteRequest* req, - const std::vector>& streams, - DeltaWriterV2** writer) { - *writer = new DeltaWriterV2(req, streams, StorageEngine::instance()); - return Status::OK(); +std::unique_ptr DeltaWriterV2::open( + WriteRequest* req, const std::vector>& streams) { + std::unique_ptr writer( + new DeltaWriterV2(req, streams, StorageEngine::instance())); + return writer; } DeltaWriterV2::DeltaWriterV2(WriteRequest* req, diff --git a/be/src/olap/delta_writer_v2.h b/be/src/olap/delta_writer_v2.h index 61ad63d0a9b513..8a102c5706d496 100644 --- a/be/src/olap/delta_writer_v2.h +++ b/be/src/olap/delta_writer_v2.h @@ -63,9 +63,8 @@ class Block; // This class is NOT thread-safe, external synchronization is required. class DeltaWriterV2 { public: - static Status open(WriteRequest* req, - const std::vector>& streams, - DeltaWriterV2** writer); + static std::unique_ptr open( + WriteRequest* req, const std::vector>& streams); ~DeltaWriterV2(); diff --git a/be/src/olap/rowset/beta_rowset_writer_v2.cpp b/be/src/olap/rowset/beta_rowset_writer_v2.cpp index e16ce5fa9fa0a8..d201ba4044e030 100644 --- a/be/src/olap/rowset/beta_rowset_writer_v2.cpp +++ b/be/src/olap/rowset/beta_rowset_writer_v2.cpp @@ -72,7 +72,7 @@ Status BetaRowsetWriterV2::init(const RowsetWriterContext& rowset_writer_context _context = rowset_writer_context; _context.segment_collector = std::make_shared>(this); _context.file_writer_creator = std::make_shared>(this); - static_cast(_segment_creator.init(_context)); + RETURN_IF_ERROR(_segment_creator.init(_context)); return Status::OK(); } diff --git a/be/src/vec/sink/delta_writer_v2_pool.cpp b/be/src/vec/sink/delta_writer_v2_pool.cpp index e714e6b1bbd4ac..b9057136d9709b 100644 --- a/be/src/vec/sink/delta_writer_v2_pool.cpp +++ b/be/src/vec/sink/delta_writer_v2_pool.cpp @@ -29,8 +29,8 @@ DeltaWriterV2Map::DeltaWriterV2Map(UniqueId load_id) : _load_id(load_id), _use_c DeltaWriterV2Map::~DeltaWriterV2Map() = default; -DeltaWriterV2* DeltaWriterV2Map::get_or_create(int64_t tablet_id, - std::function creator) { +DeltaWriterV2* DeltaWriterV2Map::get_or_create( + int64_t tablet_id, std::function()> creator) { _map.lazy_emplace(tablet_id, [&](const TabletToDeltaWriterV2Map::constructor& ctor) { ctor(tablet_id, creator()); }); diff --git a/be/src/vec/sink/delta_writer_v2_pool.h b/be/src/vec/sink/delta_writer_v2_pool.h index 414d34da671a14..8439062440a5a4 100644 --- a/be/src/vec/sink/delta_writer_v2_pool.h +++ b/be/src/vec/sink/delta_writer_v2_pool.h @@ -67,7 +67,8 @@ class DeltaWriterV2Map { void grab() { ++_use_cnt; } // get or create delta writer for the given tablet, memory is managed by DeltaWriterV2Map - DeltaWriterV2* get_or_create(int64_t tablet_id, std::function creator); + DeltaWriterV2* get_or_create(int64_t tablet_id, + std::function()> creator); // close all delta writers in this DeltaWriterV2Map if there is no other users Status close(RuntimeProfile* profile); diff --git a/be/src/vec/sink/vtablet_sink_v2.cpp b/be/src/vec/sink/vtablet_sink_v2.cpp index eba1d08acc0d20..696a66ac3fbad4 100644 --- a/be/src/vec/sink/vtablet_sink_v2.cpp +++ b/be/src/vec/sink/vtablet_sink_v2.cpp @@ -351,9 +351,7 @@ Status VOlapTableSinkV2::_write_memtable(std::shared_ptr bloc break; } } - DeltaWriterV2* delta_writer = nullptr; - static_cast(DeltaWriterV2::open(&req, streams, &delta_writer)); - return delta_writer; + return DeltaWriterV2::open(&req, streams); }); { SCOPED_TIMER(_wait_mem_limit_timer); @@ -396,7 +394,7 @@ Status VOlapTableSinkV2::close(RuntimeState* state, Status exec_status) { { SCOPED_TIMER(_close_writer_timer); // close all delta writers if this is the last user - static_cast(_delta_writer_for_tablet->close(_profile)); + RETURN_IF_ERROR(_delta_writer_for_tablet->close(_profile)); _delta_writer_for_tablet.reset(); } @@ -444,11 +442,11 @@ Status VOlapTableSinkV2::close(RuntimeState* state, Status exec_status) { LOG(INFO) << "finished to close olap table sink. load_id=" << print_id(_load_id) << ", txn_id=" << _txn_id; } else { - static_cast(_cancel(status)); + RETURN_IF_ERROR(_cancel(status)); } _close_status = status; - static_cast(DataSink::close(state, exec_status)); + RETURN_IF_ERROR(DataSink::close(state, exec_status)); return status; } diff --git a/be/test/vec/exec/delta_writer_v2_pool_test.cpp b/be/test/vec/exec/delta_writer_v2_pool_test.cpp index e68555ed68edcf..30b56b65d1150f 100644 --- a/be/test/vec/exec/delta_writer_v2_pool_test.cpp +++ b/be/test/vec/exec/delta_writer_v2_pool_test.cpp @@ -56,21 +56,9 @@ TEST_F(DeltaWriterV2PoolTest, test_map) { auto map = pool.get_or_create(load_id); EXPECT_EQ(1, pool.size()); WriteRequest req; - auto writer = map->get_or_create(100, [&req]() { - DeltaWriterV2* writer; - static_cast(DeltaWriterV2::open(&req, {}, &writer)); - return writer; - }); - auto writer2 = map->get_or_create(101, [&req]() { - DeltaWriterV2* writer; - static_cast(DeltaWriterV2::open(&req, {}, &writer)); - return writer; - }); - auto writer3 = map->get_or_create(100, [&req]() { - DeltaWriterV2* writer; - static_cast(DeltaWriterV2::open(&req, {}, &writer)); - return writer; - }); + auto writer = map->get_or_create(100, [&req]() { return DeltaWriterV2::open(&req, {}); }); + auto writer2 = map->get_or_create(101, [&req]() { return DeltaWriterV2::open(&req, {}); }); + auto writer3 = map->get_or_create(100, [&req]() { return DeltaWriterV2::open(&req, {}); }); EXPECT_EQ(2, map->size()); EXPECT_EQ(writer, writer3); EXPECT_NE(writer, writer2); From 3cdbb6e637219626793a3ef7fd06468843ad937a Mon Sep 17 00:00:00 2001 From: Pxl Date: Wed, 8 Nov 2023 10:09:37 +0800 Subject: [PATCH 25/88] [Bug](materialized-view) fix some bugs on create mv with percentile_approx (#26528) 1. percentile_approx have wrong symbol 2. fnCall.getParams() get obsolete childrens --- .../aggregate_function_percentile_approx.cpp | 11 +++- .../aggregate_function_simple_factory.cpp | 1 - .../analysis/CreateMaterializedViewStmt.java | 4 ++ .../org/apache/doris/catalog/Function.java | 3 +- .../org/apache/doris/catalog/FunctionSet.java | 9 ---- .../test_user_activity/test_user_activity.out | 12 +++++ .../test_user_activity.groovy | 52 +++++++++++++++++++ .../testProjectionMV1.groovy | 2 +- 8 files changed, 80 insertions(+), 14 deletions(-) create mode 100644 regression-test/data/mv_p0/test_user_activity/test_user_activity.out create mode 100644 regression-test/suites/mv_p0/test_user_activity/test_user_activity.groovy diff --git a/be/src/vec/aggregate_functions/aggregate_function_percentile_approx.cpp b/be/src/vec/aggregate_functions/aggregate_function_percentile_approx.cpp index 537022f194ccef..5ffac66f8f2daa 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_percentile_approx.cpp +++ b/be/src/vec/aggregate_functions/aggregate_function_percentile_approx.cpp @@ -26,14 +26,21 @@ template AggregateFunctionPtr create_aggregate_function_percentile_approx(const std::string& name, const DataTypes& argument_types, const bool result_is_nullable) { + const DataTypePtr& argument_type = remove_nullable(argument_types[0]); + WhichDataType which(argument_type); + if (which.idx != TypeIndex::Float64) { + return nullptr; + } if (argument_types.size() == 1) { return creator_without_type::create>( remove_nullable(argument_types), result_is_nullable); - } else if (argument_types.size() == 2) { + } + if (argument_types.size() == 2) { return creator_without_type::create< AggregateFunctionPercentileApproxTwoParams>( remove_nullable(argument_types), result_is_nullable); - } else if (argument_types.size() == 3) { + } + if (argument_types.size() == 3) { return creator_without_type::create< AggregateFunctionPercentileApproxThreeParams>( remove_nullable(argument_types), result_is_nullable); diff --git a/be/src/vec/aggregate_functions/aggregate_function_simple_factory.cpp b/be/src/vec/aggregate_functions/aggregate_function_simple_factory.cpp index 08e6e44311f3d1..068e2efaac48f0 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_simple_factory.cpp +++ b/be/src/vec/aggregate_functions/aggregate_function_simple_factory.cpp @@ -100,7 +100,6 @@ AggregateFunctionSimpleFactory& AggregateFunctionSimpleFactory::instance() { register_aggregate_function_replace_reader_load(instance); register_aggregate_function_window_lead_lag_first_last(instance); register_aggregate_function_HLL_union_agg(instance); - register_aggregate_function_percentile_approx(instance); }); return instance; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java index c42f3734f3d71d..b1acc545c5ab20 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/CreateMaterializedViewStmt.java @@ -518,6 +518,10 @@ private MVColumnItem buildMVColumnItem(Analyzer analyzer, FunctionCallExpr funct break; default: mvAggregateType = AggregateType.GENERIC_AGGREGATION; + if (functionCallExpr.getParams().isDistinct() || functionCallExpr.getParams().isStar()) { + throw new AnalysisException( + "The Materialized-View's generic aggregation not support star or distinct"); + } defineExpr = Function.convertToStateCombinator(functionCallExpr); type = defineExpr.type; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java index 6638eb6e367956..17d47bc4e33a25 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java @@ -20,6 +20,7 @@ import org.apache.doris.analysis.Expr; import org.apache.doris.analysis.FunctionCallExpr; import org.apache.doris.analysis.FunctionName; +import org.apache.doris.analysis.FunctionParams; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.FeMetaVersion; import org.apache.doris.common.UserException; @@ -853,7 +854,7 @@ public static FunctionCallExpr convertToStateCombinator(FunctionCallExpr fnCall) aggFunction.hasVarArgs(), aggFunction.isUserVisible()); fn.setNullableMode(NullableMode.ALWAYS_NOT_NULLABLE); fn.setBinaryType(TFunctionBinaryType.AGG_STATE); - return new FunctionCallExpr(fn, fnCall.getParams()); + return new FunctionCallExpr(fn, new FunctionParams(fnCall.getChildren())); } public static FunctionCallExpr convertToMergeCombinator(FunctionCallExpr fnCall) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java index 9390969d7a5f01..665e7b75b4b5fa 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java @@ -1318,15 +1318,6 @@ private void initAggregateBuiltins() { true, false, true, true)); //vec percentile and percentile_approx - addBuiltin(AggregateFunction.createBuiltin("percentile", - Lists.newArrayList(Type.BIGINT, Type.DOUBLE), Type.DOUBLE, Type.VARCHAR, - "", - "", - "", - "", - "", - false, true, false, true)); - addBuiltin(AggregateFunction.createBuiltin("percentile_approx", Lists.newArrayList(Type.DOUBLE, Type.DOUBLE), Type.DOUBLE, Type.VARCHAR, "", diff --git a/regression-test/data/mv_p0/test_user_activity/test_user_activity.out b/regression-test/data/mv_p0/test_user_activity/test_user_activity.out new file mode 100644 index 00000000000000..8f2bd824d04d20 --- /dev/null +++ b/regression-test/data/mv_p0/test_user_activity/test_user_activity.out @@ -0,0 +1,12 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select_base -- +2023-01-02 450.0 600.0 + +-- !select_star -- +1 2023-01-02 300 +2 2023-01-02 600 +2 2023-01-02 600 + +-- !select_group_mv -- +2023-01-02 600.0 600.0 + diff --git a/regression-test/suites/mv_p0/test_user_activity/test_user_activity.groovy b/regression-test/suites/mv_p0/test_user_activity/test_user_activity.groovy new file mode 100644 index 00000000000000..2fd50485e196db --- /dev/null +++ b/regression-test/suites/mv_p0/test_user_activity/test_user_activity.groovy @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import org.codehaus.groovy.runtime.IOGroovyMethods + +suite ("test_user_activity") { + + sql """ DROP TABLE IF EXISTS d_table; """ + + sql """ + CREATE TABLE u_axx ( + r_xx INT, + n_dx DATE, + n_duration INT + ) + DISTRIBUTED BY HASH(r_xx) + PROPERTIES ( + "replication_num" = "1" + ); + """ + + sql """INSERT INTO u_axx VALUES (1, "2023-01-02", 300);""" + sql """INSERT INTO u_axx VALUES (2, "2023-01-02", 600);""" + + qt_select_base " select n_dx, percentile_approx(n_duration, 0.5) as p50, percentile_approx(n_duration, 0.90) as p90 FROM u_axx GROUP BY n_dx; " + + createMV ("create materialized view session_distribution_2 as select n_dx, percentile_approx(n_duration, 0.5) as p50, percentile_approx(n_duration, 0.90) as p90 FROM u_axx GROUP BY n_dx;") + + sql """INSERT INTO u_axx VALUES (2, "2023-01-02", 600);""" + + qt_select_star "select * from u_axx order by 1;" + + explain { + sql("select n_dx, percentile_approx(n_duration, 0.5) as p50, percentile_approx(n_duration, 0.90) as p90 FROM u_axx GROUP BY n_dx;") + contains "(session_distribution_2)" + } + qt_select_group_mv "select n_dx, percentile_approx(n_duration, 0.5) as p50, percentile_approx(n_duration, 0.90) as p90 FROM u_axx GROUP BY n_dx;" +} diff --git a/regression-test/suites/mv_p0/ut/testProjectionMV1/testProjectionMV1.groovy b/regression-test/suites/mv_p0/ut/testProjectionMV1/testProjectionMV1.groovy index 2232e2077b3378..6a04b7fcea3efb 100644 --- a/regression-test/suites/mv_p0/ut/testProjectionMV1/testProjectionMV1.groovy +++ b/regression-test/suites/mv_p0/ut/testProjectionMV1/testProjectionMV1.groovy @@ -34,7 +34,6 @@ suite ("testProjectionMV1") { sql """insert into emps values("2020-01-01",1,"a",1,1,1);""" sql """insert into emps values("2020-01-02",2,"b",2,2,2);""" - sql """set enable_nereids_planner=false""" test { sql "create materialized view emps_mv as select deptno, empid from emps t order by deptno;" exception "errCode = 2," @@ -57,6 +56,7 @@ suite ("testProjectionMV1") { } qt_select_mv "select empid, deptno from emps order by empid;" + sql """set enable_nereids_planner=false""" // need fix it on nereids explain { sql("select empid, sum(deptno) from emps group by empid order by empid;") contains "(emps_mv)" From daea751a986823bf5858704663d58f49fd5dfb39 Mon Sep 17 00:00:00 2001 From: Yulei-Yang Date: Wed, 8 Nov 2023 10:25:15 +0800 Subject: [PATCH 26/88] [Improvement](auditlog) add column catalog for audit log and audit log table (#26403) --- docs/en/docs/ecosystem/audit-plugin.md | 2 ++ docs/zh-CN/docs/ecosystem/audit-plugin.md | 2 ++ .../src/main/java/org/apache/doris/plugin/AuditEvent.java | 7 +++++++ .../src/main/java/org/apache/doris/qe/AuditLogHelper.java | 5 +++++ .../org/apache/doris/plugin/audit/AuditLoaderPlugin.java | 1 + .../org/apache/doris/plugin/audit/DorisStreamLoader.java | 4 ++-- pytest/deploy/start.py | 1 + 7 files changed, 20 insertions(+), 2 deletions(-) diff --git a/docs/en/docs/ecosystem/audit-plugin.md b/docs/en/docs/ecosystem/audit-plugin.md index a355a75e5948e8..d63c15f8b940e8 100644 --- a/docs/en/docs/ecosystem/audit-plugin.md +++ b/docs/en/docs/ecosystem/audit-plugin.md @@ -87,6 +87,7 @@ create table doris_audit_db__.doris_audit_log_tbl__ `time` datetime not null comment "Query start time", client_ip varchar(32) comment "Client IP", user varchar(64) comment "User name", + catalog varchar(128) comment "Catalog of this query", db varchar(96) comment "Database of this query", state varchar(8) comment "Query result state. EOF, ERR, OK", error_code int comment "Error code of failing query.", @@ -123,6 +124,7 @@ create table doris_audit_db__.doris_slow_log_tbl__ `time` datetime not null comment "Query start time", client_ip varchar(32) comment "Client IP", user varchar(64) comment "User name", + catalog varchar(128) comment "Catalog of this query", db varchar(96) comment "Database of this query", state varchar(8) comment "Query result state. EOF, ERR, OK", error_code int comment "Error code of failing query.", diff --git a/docs/zh-CN/docs/ecosystem/audit-plugin.md b/docs/zh-CN/docs/ecosystem/audit-plugin.md index 7fe4549926fcf1..f700ce28d0c07d 100644 --- a/docs/zh-CN/docs/ecosystem/audit-plugin.md +++ b/docs/zh-CN/docs/ecosystem/audit-plugin.md @@ -93,6 +93,7 @@ create table doris_audit_db__.doris_audit_log_tbl__ `time` datetime not null comment "Query start time", client_ip varchar(32) comment "Client IP", user varchar(64) comment "User name", + catalog varchar(128) comment "Catalog of this query", db varchar(96) comment "Database of this query", state varchar(8) comment "Query result state. EOF, ERR, OK", error_code int comment "Error code of failing query.", @@ -129,6 +130,7 @@ create table doris_audit_db__.doris_slow_log_tbl__ `time` datetime not null comment "Query start time", client_ip varchar(32) comment "Client IP", user varchar(64) comment "User name", + catalog varchar(128) comment "Catalog of this query", db varchar(96) comment "Database of this query", state varchar(8) comment "Query result state. EOF, ERR, OK", error_code int comment "Error code of failing query.", diff --git a/fe/fe-core/src/main/java/org/apache/doris/plugin/AuditEvent.java b/fe/fe-core/src/main/java/org/apache/doris/plugin/AuditEvent.java index dbef8321b54542..8eb539706cbddf 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/plugin/AuditEvent.java +++ b/fe/fe-core/src/main/java/org/apache/doris/plugin/AuditEvent.java @@ -56,6 +56,8 @@ public enum EventType { public String clientIp = ""; @AuditField(value = "User") public String user = ""; + @AuditField(value = "Catalog") + public String catalog = ""; @AuditField(value = "Db") public String db = ""; @AuditField(value = "State") @@ -131,6 +133,11 @@ public AuditEventBuilder setUser(String user) { return this; } + public AuditEventBuilder setCatalog(String catalog) { + auditEvent.catalog = catalog; + return this; + } + public AuditEventBuilder setDb(String db) { auditEvent.db = db; return this; diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/AuditLogHelper.java b/fe/fe-core/src/main/java/org/apache/doris/qe/AuditLogHelper.java index 40f870eee11c0c..0ed0e9002541b9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/AuditLogHelper.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/AuditLogHelper.java @@ -62,6 +62,11 @@ public static void logAuditLog(ConnectContext ctx, String origStmt, StatementBas .setWorkloadGroup(ctx.getWorkloadGroupName()) .setFuzzyVariables(!printFuzzyVariables ? "" : ctx.getSessionVariable().printFuzzyVariables()); + // when doric fe is booting, current catalog may not be set + if (ctx.getCurrentCatalog() != null) { + ctx.getAuditEventBuilder().setCatalog(ctx.getCurrentCatalog().getName()); + } + if (ctx.getState().isQuery()) { MetricRepo.COUNTER_QUERY_ALL.increase(1L); MetricRepo.USER_COUNTER_QUERY_ALL.getOrAdd(ctx.getQualifiedUser()).increase(1L); diff --git a/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java b/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java index 3cfb0eeeaee3a5..75c45f56f61e46 100755 --- a/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java +++ b/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/AuditLoaderPlugin.java @@ -163,6 +163,7 @@ private void fillLogBuffer(AuditEvent event, StringBuilder logBuffer) { logBuffer.append(longToTimeString(event.timestamp)).append("\t"); logBuffer.append(event.clientIp).append("\t"); logBuffer.append(event.user).append("\t"); + logBuffer.append(event.catalog).append("\t"); logBuffer.append(event.db).append("\t"); logBuffer.append(event.state).append("\t"); logBuffer.append(event.errorCode).append("\t"); diff --git a/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/DorisStreamLoader.java b/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/DorisStreamLoader.java index d389f0dfa8156c..7b568f0a04d9a4 100644 --- a/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/DorisStreamLoader.java +++ b/fe_plugins/auditloader/src/main/java/org/apache/doris/plugin/audit/DorisStreamLoader.java @@ -71,7 +71,7 @@ private HttpURLConnection getConnection(String urlStr, String label, String clus conn.addRequestProperty("label", label); conn.addRequestProperty("max_filter_ratio", "1.0"); - conn.addRequestProperty("columns", "query_id, `time`, client_ip, user, db, state, error_code, error_message, " + + conn.addRequestProperty("columns", "query_id, `time`, client_ip, user, catalog, db, state, error_code, error_message, " + "query_time, scan_bytes, scan_rows, return_rows, stmt_id, is_query, frontend_ip, cpu_time_ms, sql_hash, " + "sql_digest, peak_memory_bytes, stmt"); @@ -88,7 +88,7 @@ private String toCurl(HttpURLConnection conn) { sb.append("-H \"").append("Expect\":").append("\"100-continue\" \\\n "); sb.append("-H \"").append("Content-Type\":").append("\"text/plain; charset=UTF-8\" \\\n "); sb.append("-H \"").append("max_filter_ratio\":").append("\"1.0\" \\\n "); - sb.append("-H \"").append("columns\":").append("\"query_id, time, client_ip, user, db, state, error_code, " + + sb.append("-H \"").append("columns\":").append("\"query_id, time, client_ip, user, catalog, db, state, error_code, " + "error_message, query_time, scan_bytes, scan_rows, return_rows, stmt_id, is_query, frontend_ip, " + "cpu_time_ms, sql_hash, sql_digest, peak_memory_bytes, stmt\" \\\n "); sb.append("\"").append(conn.getURL()).append("\""); diff --git a/pytest/deploy/start.py b/pytest/deploy/start.py index 608d477fe9dde7..dc6498b9e9afec 100644 --- a/pytest/deploy/start.py +++ b/pytest/deploy/start.py @@ -181,6 +181,7 @@ def add_auditload_plugin(): \`time\` datetime not null comment 'Query start time', \ client_ip varchar(32) comment 'Client IP', \ user varchar(64) comment 'User name', \ + catalog varchar(128) comment 'Catalog of this query', \ db varchar(96) comment 'Database of this query', \ state varchar(8) comment 'Query result state. EOF, ERR, OK', \ query_time bigint comment 'Query execution time in millisecond', \ From b7c81bc73625b26df746fc2213980c16b9d8f1a0 Mon Sep 17 00:00:00 2001 From: Calvin Kirs Date: Wed, 8 Nov 2023 10:42:22 +0800 Subject: [PATCH 27/88] [Chore](ci)Temporarily cancel the mandatory restrictions of ShellCheck (#26553) To let #26525 pass. --- .asf.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.asf.yaml b/.asf.yaml index f8b7e0913cf61b..59f6fd20e75068 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -59,7 +59,6 @@ github: - BE UT (Doris BE UT) - Build Broker - Build Documents - - ShellCheck - clickbench-new (clickbench) - Build Third Party Libraries (Linux) - Build Third Party Libraries (macOS) From 806461721c897e7cb413b3a1d61e5f488126b0dd Mon Sep 17 00:00:00 2001 From: morrySnow <101034200+morrySnow@users.noreply.github.com> Date: Wed, 8 Nov 2023 10:43:37 +0800 Subject: [PATCH 28/88] [opt](Nereids) remove Nondeterministic trait from date related functions (#26444) --- .../doris/analysis/ExpressionFunctions.java | 7 +----- .../functions/Nondeterministic.java | 8 ------- .../functions/executable/DateTimeAcquire.java | 23 ++++++++++--------- .../expressions/functions/scalar/Random.java | 5 ++++ .../functions/scalar/UnixTimestamp.java | 10 +------- .../expressions/functions/scalar/Uuid.java | 5 ++++ .../functions/scalar/UuidNumeric.java | 5 ++++ .../nereids/trees/plans/PlanVisitorTest.java | 16 ++++++------- .../datatype/test_date_acquire.groovy | 2 +- 9 files changed, 38 insertions(+), 43 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java index a45954a9b93c7c..ea63a8ffabeac3 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ExpressionFunctions.java @@ -52,13 +52,8 @@ public enum ExpressionFunctions { private static final Logger LOG = LogManager.getLogger(ExpressionFunctions.class); private ImmutableMultimap functions; public static final Set unfixedFn = ImmutableSet.of( - "now", - "current_time", - "current_date", - "utc_timestamp", "uuid", - "random", - "unix_timestamp" + "random" ); private ExpressionFunctions() { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/Nondeterministic.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/Nondeterministic.java index 88955c0c4da07c..56aa5ebb3b9ccf 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/Nondeterministic.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/Nondeterministic.java @@ -17,8 +17,6 @@ package org.apache.doris.nereids.trees.expressions.functions; -import org.apache.doris.qe.ConnectContext; - /** * Nondeterministic functions. * @@ -26,10 +24,4 @@ * */ public interface Nondeterministic extends ExpressionTrait { - @Override - default boolean foldable() { - return ConnectContext.get() == null - || ConnectContext.get().getSessionVariable() == null - || ConnectContext.get().getSessionVariable().isEnableFoldNondeterministicFn(); - } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeAcquire.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeAcquire.java index e5dca783fd4bee..17403bd83c0770 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeAcquire.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/DateTimeAcquire.java @@ -86,18 +86,19 @@ public static Expression currentDate() { return DateLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone())); } - /** - * date acquire function: current_time - */ - @ExecFunction(name = "curtime", argTypes = {}, returnType = "DATETIME") - public static Expression curTime() { - return DateTimeLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone())); - } + // comment these function temporally until we support TimeLiteral + // /** + // * date acquire function: current_time + // */ + // @ExecFunction(name = "curtime", argTypes = {}, returnType = "TIME") + // public static Expression curTime() { + // return DateTimeLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone())); + // } - @ExecFunction(name = "current_time", argTypes = {}, returnType = "DATETIME") - public static Expression currentTime() { - return DateTimeLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone())); - } + // @ExecFunction(name = "current_time", argTypes = {}, returnType = "TIME") + // public static Expression currentTime() { + // return DateTimeLiteral.fromJavaDateType(LocalDateTime.now(DateUtils.getTimeZone())); + // } /** * date transformation function: unix_timestamp diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java index 1ee251c305dac5..29530adfa0aa4e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Random.java @@ -70,6 +70,11 @@ public boolean nullable() { } } + @Override + public boolean foldable() { + return false; + } + /** * withChildren. */ diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UnixTimestamp.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UnixTimestamp.java index 20958dd45af4f5..bdeabb74c89380 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UnixTimestamp.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UnixTimestamp.java @@ -40,7 +40,7 @@ * ScalarFunction 'unix_timestamp'. This class is generated by GenerateFunction. */ public class UnixTimestamp extends ScalarFunction - implements Nondeterministic, ExplicitlyCastableSignature, PropagateNullableOnDateLikeV2Args { + implements ExplicitlyCastableSignature, PropagateNullableOnDateLikeV2Args, Nondeterministic { private static final List SIGNATURES = ImmutableList.of( FunctionSignature.ret(IntegerType.INSTANCE).args(), @@ -101,14 +101,6 @@ public UnixTimestamp withChildren(List children) { } } - @Override - public boolean foldable() { - if (children.size() != 0) { - return true; - } - return Nondeterministic.super.foldable(); - } - @Override public List getSignatures() { return SIGNATURES; diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Uuid.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Uuid.java index 2f0f162b5fcefb..8949290783256b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Uuid.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/Uuid.java @@ -46,6 +46,11 @@ public Uuid() { super("uuid"); } + @Override + public boolean foldable() { + return false; + } + @Override public R accept(ExpressionVisitor visitor, C context) { return visitor.visitUuid(this, context); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidNumeric.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidNumeric.java index 3e2267b4370c74..bbbd2e81a9994a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidNumeric.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/scalar/UuidNumeric.java @@ -46,6 +46,11 @@ public UuidNumeric() { super("uuid_numeric"); } + @Override + public boolean foldable() { + return false; + } + @Override public R accept(ExpressionVisitor visitor, C context) { return visitor.visitUuidNumeric(this, context); diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanVisitorTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanVisitorTest.java index e70470c46820d1..c6ca20577cc070 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanVisitorTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/trees/plans/PlanVisitorTest.java @@ -21,8 +21,8 @@ import org.apache.doris.catalog.TableIf.TableType; import org.apache.doris.nereids.trees.TreeNode; import org.apache.doris.nereids.trees.expressions.Expression; -import org.apache.doris.nereids.trees.expressions.functions.scalar.CurrentDate; -import org.apache.doris.nereids.trees.expressions.functions.scalar.Now; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Random; +import org.apache.doris.nereids.trees.expressions.functions.scalar.Uuid; import org.apache.doris.nereids.trees.plans.physical.PhysicalPlan; import org.apache.doris.nereids.trees.plans.visitor.NondeterministicFunctionCollector; import org.apache.doris.nereids.trees.plans.visitor.TableCollector; @@ -76,7 +76,7 @@ protected void runBeforeAll() throws Exception { + "\"replication_num\" = \"1\"\n" + ");"); - createView("CREATE VIEW `view1` AS SELECT t1.*, current_date() FROM\n" + createView("CREATE VIEW `view1` AS SELECT t1.*, random() FROM\n" + "`table1` t1 LEFT JOIN\n" + "`table2` t2 ON t1.c1 = t2.c1;"); } @@ -84,7 +84,7 @@ protected void runBeforeAll() throws Exception { @Test public void test1() { PlanChecker.from(connectContext) - .checkPlannerResult("SELECT *, now() FROM table1 " + .checkPlannerResult("SELECT *, random() FROM table1 " + "LEFT SEMI JOIN table2 ON table1.c1 = table2.c1 " + "WHERE table1.c1 IN (SELECT c1 FROM table2) OR table1.c1 < 10", nereidsPlanner -> { @@ -93,7 +93,7 @@ public void test1() { // Check nondeterministic collect physicalPlan.accept(NondeterministicFunctionCollector.INSTANCE, collectResult); Assertions.assertEquals(1, collectResult.size()); - Assertions.assertTrue(collectResult.get(0) instanceof Now); + Assertions.assertTrue(collectResult.get(0) instanceof Random); // Check get tables TableCollectorContext collectorContext = new TableCollector.TableCollectorContext(Sets.newHashSet(TableType.OLAP)); @@ -114,7 +114,7 @@ public void test1() { @Test public void test2() { PlanChecker.from(connectContext) - .checkPlannerResult("SELECT view1.*, now() FROM view1 " + .checkPlannerResult("SELECT view1.*, uuid() FROM view1 " + "LEFT SEMI JOIN table2 ON view1.c1 = table2.c1 " + "WHERE view1.c1 IN (SELECT c1 FROM table2) OR view1.c1 < 10", nereidsPlanner -> { @@ -123,8 +123,8 @@ public void test2() { // Check nondeterministic collect physicalPlan.accept(NondeterministicFunctionCollector.INSTANCE, collectResult); Assertions.assertEquals(2, collectResult.size()); - Assertions.assertTrue(collectResult.get(0) instanceof Now); - Assertions.assertTrue(collectResult.get(1) instanceof CurrentDate); + Assertions.assertTrue(collectResult.get(0) instanceof Uuid); + Assertions.assertTrue(collectResult.get(1) instanceof Random); // Check get tables TableCollectorContext collectorContext = new TableCollector.TableCollectorContext(Sets.newHashSet(TableType.OLAP)); diff --git a/regression-test/suites/nereids_p0/datatype/test_date_acquire.groovy b/regression-test/suites/nereids_p0/datatype/test_date_acquire.groovy index b6afad759d34ec..981b28eac4065c 100644 --- a/regression-test/suites/nereids_p0/datatype/test_date_acquire.groovy +++ b/regression-test/suites/nereids_p0/datatype/test_date_acquire.groovy @@ -20,7 +20,7 @@ suite("test_date_acquire") { sql 'set enable_fallback_to_original_planner=false' sql 'set enable_fold_nondeterministic_fn=true' - String res = sql 'explain select now(), now(3), curdate(), current_date(), curtime(), current_time(), current_timestamp(), current_timestamp(3)' + String res = sql 'explain select now(), now(3), curdate(), current_date(), current_timestamp(), current_timestamp(3)' res = res.split('VUNION')[1] assertFalse(res.contains("()") || res.contains("(3)")) From 1544110c1b9484226ac4a853a506983c2e26f9f0 Mon Sep 17 00:00:00 2001 From: Xinyi Zou Date: Wed, 8 Nov 2023 10:50:42 +0800 Subject: [PATCH 29/88] [feature-wip](arrow-flight)(step4) Support other DML and DDL statements, besides `Select` (#25919) Design Documentation Linked to #25514 --- be/src/runtime/result_buffer_mgr.cpp | 26 +- be/src/runtime/result_buffer_mgr.h | 15 +- .../arrow_flight_batch_reader.cpp | 16 +- be/src/service/internal_service.cpp | 20 +- be/src/util/arrow/row_batch.cpp | 32 +- be/src/util/arrow/row_batch.h | 7 +- .../vec/sink/varrow_flight_result_writer.cpp | 13 +- be/src/vec/sink/varrow_flight_result_writer.h | 5 +- be/src/vec/sink/vmemory_scratch_sink.cpp | 2 - be/src/vec/sink/vmemory_scratch_sink.h | 2 - be/src/vec/sink/vresult_sink.cpp | 12 +- .../org/apache/doris/common/ErrorCode.java | 5 +- .../apache/doris/mysql/AcceptListener.java | 3 +- .../org/apache/doris/mysql/MysqlCommand.java | 1 + .../org/apache/doris/qe/ConnectContext.java | 119 +++++-- .../org/apache/doris/qe/ConnectProcessor.java | 313 ++++-------------- .../org/apache/doris/qe/ConnectScheduler.java | 4 +- .../java/org/apache/doris/qe/Coordinator.java | 35 +- .../doris/qe/MysqlConnectProcessor.java | 272 +++++++++++++++ .../java/org/apache/doris/qe/QueryState.java | 1 + .../org/apache/doris/qe/StmtExecutor.java | 196 ++++++----- .../doris/service/FrontendServiceImpl.java | 14 +- .../arrowflight/DorisFlightSqlProducer.java | 140 ++++++-- ...or.java => FlightSqlConnectProcessor.java} | 155 ++++----- .../arrowflight/results/FlightSqlChannel.java | 147 ++++++++ .../results/FlightSqlResultCacheEntry.java | 64 ++++ .../sessions/FlightSessionsManager.java | 4 +- .../FlightSessionsWithTokenManager.java | 1 + .../sessions/FlightSqlConnectContext.java | 104 ++++++ .../org/apache/doris/qe/StmtExecutorTest.java | 9 + 30 files changed, 1137 insertions(+), 600 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/qe/MysqlConnectProcessor.java rename fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/{FlightStatementExecutor.java => FlightSqlConnectProcessor.java} (65%) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/results/FlightSqlChannel.java create mode 100644 fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/results/FlightSqlResultCacheEntry.java create mode 100644 fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSqlConnectContext.java diff --git a/be/src/runtime/result_buffer_mgr.cpp b/be/src/runtime/result_buffer_mgr.cpp index 9dbe228bcd9890..a2009c5ec3c970 100644 --- a/be/src/runtime/result_buffer_mgr.cpp +++ b/be/src/runtime/result_buffer_mgr.cpp @@ -109,21 +109,21 @@ std::shared_ptr ResultBufferMgr::find_control_block(const TU return std::shared_ptr(); } -void ResultBufferMgr::register_row_descriptor(const TUniqueId& query_id, - const RowDescriptor& row_desc) { - std::unique_lock wlock(_row_descriptor_map_lock); - _row_descriptor_map.insert(std::make_pair(query_id, row_desc)); +void ResultBufferMgr::register_arrow_schema(const TUniqueId& query_id, + const std::shared_ptr& arrow_schema) { + std::unique_lock wlock(_arrow_schema_map_lock); + _arrow_schema_map.insert(std::make_pair(query_id, arrow_schema)); } -RowDescriptor ResultBufferMgr::find_row_descriptor(const TUniqueId& query_id) { - std::shared_lock rlock(_row_descriptor_map_lock); - RowDescriptorMap::iterator iter = _row_descriptor_map.find(query_id); +std::shared_ptr ResultBufferMgr::find_arrow_schema(const TUniqueId& query_id) { + std::shared_lock rlock(_arrow_schema_map_lock); + auto iter = _arrow_schema_map.find(query_id); - if (_row_descriptor_map.end() != iter) { + if (_arrow_schema_map.end() != iter) { return iter->second; } - return RowDescriptor(); + return nullptr; } void ResultBufferMgr::fetch_data(const PUniqueId& finst_id, GetResultBatchCtx* ctx) { @@ -162,11 +162,11 @@ Status ResultBufferMgr::cancel(const TUniqueId& query_id) { } { - std::unique_lock wlock(_row_descriptor_map_lock); - RowDescriptorMap::iterator row_desc_iter = _row_descriptor_map.find(query_id); + std::unique_lock wlock(_arrow_schema_map_lock); + auto arrow_schema_iter = _arrow_schema_map.find(query_id); - if (_row_descriptor_map.end() != row_desc_iter) { - _row_descriptor_map.erase(row_desc_iter); + if (_arrow_schema_map.end() != arrow_schema_iter) { + _arrow_schema_map.erase(arrow_schema_iter); } } diff --git a/be/src/runtime/result_buffer_mgr.h b/be/src/runtime/result_buffer_mgr.h index 4e5cd38a7264b7..7995496cbf9c6d 100644 --- a/be/src/runtime/result_buffer_mgr.h +++ b/be/src/runtime/result_buffer_mgr.h @@ -29,12 +29,12 @@ #include "common/status.h" #include "gutil/ref_counted.h" -#include "runtime/descriptors.h" #include "util/countdown_latch.h" #include "util/hash_util.hpp" namespace arrow { class RecordBatch; +class Schema; } // namespace arrow namespace doris { @@ -66,8 +66,9 @@ class ResultBufferMgr { // fetch data result to Arrow Flight Server Status fetch_arrow_data(const TUniqueId& finst_id, std::shared_ptr* result); - void register_row_descriptor(const TUniqueId& query_id, const RowDescriptor& row_desc); - RowDescriptor find_row_descriptor(const TUniqueId& query_id); + void register_arrow_schema(const TUniqueId& query_id, + const std::shared_ptr& arrow_schema); + std::shared_ptr find_arrow_schema(const TUniqueId& query_id); // cancel Status cancel(const TUniqueId& fragment_id); @@ -78,7 +79,7 @@ class ResultBufferMgr { private: using BufferMap = std::unordered_map>; using TimeoutMap = std::map>; - using RowDescriptorMap = std::unordered_map; + using ArrowSchemaMap = std::unordered_map>; std::shared_ptr find_control_block(const TUniqueId& query_id); @@ -90,10 +91,10 @@ class ResultBufferMgr { std::shared_mutex _buffer_map_lock; // buffer block map BufferMap _buffer_map; - // lock for descriptor map - std::shared_mutex _row_descriptor_map_lock; + // lock for arrow schema map + std::shared_mutex _arrow_schema_map_lock; // for arrow flight - RowDescriptorMap _row_descriptor_map; + ArrowSchemaMap _arrow_schema_map; // lock for timeout map std::mutex _timeout_lock; diff --git a/be/src/service/arrow_flight/arrow_flight_batch_reader.cpp b/be/src/service/arrow_flight/arrow_flight_batch_reader.cpp index 8a0f1e67859494..d2b45a0b77c6ef 100644 --- a/be/src/service/arrow_flight/arrow_flight_batch_reader.cpp +++ b/be/src/service/arrow_flight/arrow_flight_batch_reader.cpp @@ -39,18 +39,12 @@ ArrowFlightBatchReader::ArrowFlightBatchReader(std::shared_ptr s arrow::Result> ArrowFlightBatchReader::Create( const std::shared_ptr& statement_) { // Make sure that FE send the fragment to BE and creates the BufferControlBlock before returning ticket - // to the ADBC client, so that the row_descriptor and control block can be found. - RowDescriptor row_desc = - ExecEnv::GetInstance()->result_mgr()->find_row_descriptor(statement_->query_id); - if (row_desc.equals(RowDescriptor())) { + // to the ADBC client, so that the schema and control block can be found. + auto schema = ExecEnv::GetInstance()->result_mgr()->find_arrow_schema(statement_->query_id); + if (schema == nullptr) { ARROW_RETURN_NOT_OK(arrow::Status::Invalid(fmt::format( - "Schema RowDescriptor Not Found, queryid: {}", print_id(statement_->query_id)))); - } - std::shared_ptr schema; - auto st = convert_to_arrow_schema(row_desc, &schema); - if (UNLIKELY(!st.ok())) { - LOG(WARNING) << st.to_string(); - ARROW_RETURN_NOT_OK(to_arrow_status(st)); + "not found arrow flight schema, maybe query has been canceled, queryid: {}", + print_id(statement_->query_id)))); } std::shared_ptr result(new ArrowFlightBatchReader(statement_, schema)); return result; diff --git a/be/src/service/internal_service.cpp b/be/src/service/internal_service.cpp index dba01f1b6685c1..52b448a5f6db92 100644 --- a/be/src/service/internal_service.cpp +++ b/be/src/service/internal_service.cpp @@ -718,23 +718,19 @@ void PInternalServiceImpl::fetch_arrow_flight_schema(google::protobuf::RpcContro google::protobuf::Closure* done) { bool ret = _light_work_pool.try_offer([request, result, done]() { brpc::ClosureGuard closure_guard(done); - RowDescriptor row_desc = ExecEnv::GetInstance()->result_mgr()->find_row_descriptor( - UniqueId(request->finst_id()).to_thrift()); - if (row_desc.equals(RowDescriptor())) { - auto st = Status::NotFound("not found row descriptor"); - st.to_protobuf(result->mutable_status()); - return; - } - - std::shared_ptr schema; - auto st = convert_to_arrow_schema(row_desc, &schema); - if (UNLIKELY(!st.ok())) { + std::shared_ptr schema = + ExecEnv::GetInstance()->result_mgr()->find_arrow_schema( + UniqueId(request->finst_id()).to_thrift()); + if (schema == nullptr) { + LOG(INFO) << "not found arrow flight schema, maybe query has been canceled"; + auto st = Status::NotFound( + "not found arrow flight schema, maybe query has been canceled"); st.to_protobuf(result->mutable_status()); return; } std::string schema_str; - st = serialize_arrow_schema(row_desc, &schema, &schema_str); + auto st = serialize_arrow_schema(&schema, &schema_str); if (st.ok()) { result->set_schema(std::move(schema_str)); } diff --git a/be/src/util/arrow/row_batch.cpp b/be/src/util/arrow/row_batch.cpp index 6a44da2ec6b642..6662f2e0ba7aee 100644 --- a/be/src/util/arrow/row_batch.cpp +++ b/be/src/util/arrow/row_batch.cpp @@ -39,6 +39,8 @@ #include "runtime/types.h" #include "util/arrow/block_convertor.h" #include "vec/core/block.h" +#include "vec/exprs/vexpr.h" +#include "vec/exprs/vexpr_context.h" namespace doris { @@ -163,6 +165,22 @@ Status convert_to_arrow_schema(const RowDescriptor& row_desc, return Status::OK(); } +Status convert_expr_ctxs_arrow_schema(const vectorized::VExprContextSPtrs& output_vexpr_ctxs, + std::shared_ptr* result) { + std::vector> fields; + for (auto expr_ctx : output_vexpr_ctxs) { + std::shared_ptr arrow_type; + auto root_expr = expr_ctx->root(); + RETURN_IF_ERROR(convert_to_arrow_type(root_expr->type(), &arrow_type)); + auto field_name = root_expr->is_slot_ref() ? root_expr->expr_name() + : root_expr->data_type()->get_name(); + fields.push_back( + std::make_shared(field_name, arrow_type, root_expr->is_nullable())); + } + *result = arrow::schema(std::move(fields)); + return Status::OK(); +} + Status serialize_record_batch(const arrow::RecordBatch& record_batch, std::string* result) { // create sink memory buffer outputstream with the computed capacity int64_t capacity; @@ -206,15 +224,13 @@ Status serialize_record_batch(const arrow::RecordBatch& record_batch, std::strin return Status::OK(); } -Status serialize_arrow_schema(RowDescriptor row_desc, std::shared_ptr* schema, - std::string* result) { - std::vector slots; - for (auto tuple_desc : row_desc.tuple_descriptors()) { - slots.insert(slots.end(), tuple_desc->slots().begin(), tuple_desc->slots().end()); +Status serialize_arrow_schema(std::shared_ptr* schema, std::string* result) { + auto make_empty_result = arrow::RecordBatch::MakeEmpty(*schema); + if (!make_empty_result.ok()) { + return Status::InternalError("serialize_arrow_schema failed, reason: {}", + make_empty_result.status().ToString()); } - auto block = vectorized::Block(slots, 0); - std::shared_ptr batch; - RETURN_IF_ERROR(convert_to_arrow_batch(block, *schema, arrow::default_memory_pool(), &batch)); + auto batch = make_empty_result.ValueOrDie(); return serialize_record_batch(*batch, result); } diff --git a/be/src/util/arrow/row_batch.h b/be/src/util/arrow/row_batch.h index 1bd408754f1b58..ddffc3324d3451 100644 --- a/be/src/util/arrow/row_batch.h +++ b/be/src/util/arrow/row_batch.h @@ -23,6 +23,7 @@ #include "common/status.h" #include "runtime/types.h" #include "vec/core/block.h" +#include "vec/exprs/vexpr_fwd.h" // This file will convert Doris RowBatch to/from Arrow's RecordBatch // RowBatch is used by Doris query engine to exchange data between @@ -49,9 +50,11 @@ Status convert_to_arrow_schema(const RowDescriptor& row_desc, Status convert_block_arrow_schema(const vectorized::Block& block, std::shared_ptr* result); +Status convert_expr_ctxs_arrow_schema(const vectorized::VExprContextSPtrs& output_vexpr_ctxs, + std::shared_ptr* result); + Status serialize_record_batch(const arrow::RecordBatch& record_batch, std::string* result); -Status serialize_arrow_schema(RowDescriptor row_desc, std::shared_ptr* schema, - std::string* result); +Status serialize_arrow_schema(std::shared_ptr* schema, std::string* result); } // namespace doris diff --git a/be/src/vec/sink/varrow_flight_result_writer.cpp b/be/src/vec/sink/varrow_flight_result_writer.cpp index 4a71e10df426a6..771040bfb8b477 100644 --- a/be/src/vec/sink/varrow_flight_result_writer.cpp +++ b/be/src/vec/sink/varrow_flight_result_writer.cpp @@ -27,14 +27,13 @@ namespace doris { namespace vectorized { -VArrowFlightResultWriter::VArrowFlightResultWriter(BufferControlBlock* sinker, - const VExprContextSPtrs& output_vexpr_ctxs, - RuntimeProfile* parent_profile, - const RowDescriptor& row_desc) +VArrowFlightResultWriter::VArrowFlightResultWriter( + BufferControlBlock* sinker, const VExprContextSPtrs& output_vexpr_ctxs, + RuntimeProfile* parent_profile, const std::shared_ptr& arrow_schema) : _sinker(sinker), _output_vexpr_ctxs(output_vexpr_ctxs), _parent_profile(parent_profile), - _row_desc(row_desc) {} + _arrow_schema(arrow_schema) {} Status VArrowFlightResultWriter::init(RuntimeState* state) { _init_profile(); @@ -42,8 +41,6 @@ Status VArrowFlightResultWriter::init(RuntimeState* state) { return Status::InternalError("sinker is NULL pointer."); } _is_dry_run = state->query_options().dry_run_query; - // generate the arrow schema - RETURN_IF_ERROR(convert_to_arrow_schema(_row_desc, &_arrow_schema)); return Status::OK(); } @@ -100,7 +97,7 @@ bool VArrowFlightResultWriter::can_sink() { return _sinker->can_sink(); } -Status VArrowFlightResultWriter::close(Status) { +Status VArrowFlightResultWriter::close(Status st) { COUNTER_SET(_sent_rows_counter, _written_rows); COUNTER_UPDATE(_bytes_sent_counter, _bytes_sent); return Status::OK(); diff --git a/be/src/vec/sink/varrow_flight_result_writer.h b/be/src/vec/sink/varrow_flight_result_writer.h index 7aa8ec6824a7e6..02faebfddb3ad5 100644 --- a/be/src/vec/sink/varrow_flight_result_writer.h +++ b/be/src/vec/sink/varrow_flight_result_writer.h @@ -31,7 +31,6 @@ namespace doris { class BufferControlBlock; class RuntimeState; -class RowDescriptor; namespace vectorized { class Block; @@ -39,7 +38,8 @@ class Block; class VArrowFlightResultWriter final : public ResultWriter { public: VArrowFlightResultWriter(BufferControlBlock* sinker, const VExprContextSPtrs& output_vexpr_ctxs, - RuntimeProfile* parent_profile, const RowDescriptor& row_desc); + RuntimeProfile* parent_profile, + const std::shared_ptr& arrow_schema); Status init(RuntimeState* state) override; @@ -72,7 +72,6 @@ class VArrowFlightResultWriter final : public ResultWriter { uint64_t _bytes_sent = 0; - const RowDescriptor& _row_desc; std::shared_ptr _arrow_schema; }; } // namespace vectorized diff --git a/be/src/vec/sink/vmemory_scratch_sink.cpp b/be/src/vec/sink/vmemory_scratch_sink.cpp index f9192d5c79f140..d4f0d4521c04b2 100644 --- a/be/src/vec/sink/vmemory_scratch_sink.cpp +++ b/be/src/vec/sink/vmemory_scratch_sink.cpp @@ -56,8 +56,6 @@ Status MemoryScratchSink::_prepare_vexpr(RuntimeState* state) { RETURN_IF_ERROR(VExpr::create_expr_trees(_t_output_expr, _output_vexpr_ctxs)); // Prepare the exprs to run. RETURN_IF_ERROR(VExpr::prepare(_output_vexpr_ctxs, state, _row_desc)); - // generate the arrow schema - RETURN_IF_ERROR(convert_to_arrow_schema(_row_desc, &_arrow_schema)); return Status::OK(); } diff --git a/be/src/vec/sink/vmemory_scratch_sink.h b/be/src/vec/sink/vmemory_scratch_sink.h index e91d130547acca..c9a6922336ce29 100644 --- a/be/src/vec/sink/vmemory_scratch_sink.h +++ b/be/src/vec/sink/vmemory_scratch_sink.h @@ -65,8 +65,6 @@ class MemoryScratchSink final : public DataSink { private: Status _prepare_vexpr(RuntimeState* state); - std::shared_ptr _arrow_schema; - BlockQueueSharedPtr _queue; // Owned by the RuntimeState. diff --git a/be/src/vec/sink/vresult_sink.cpp b/be/src/vec/sink/vresult_sink.cpp index b3a2d3bae7f7b9..d5ca67b76c7985 100644 --- a/be/src/vec/sink/vresult_sink.cpp +++ b/be/src/vec/sink/vresult_sink.cpp @@ -33,6 +33,7 @@ #include "runtime/exec_env.h" #include "runtime/result_buffer_mgr.h" #include "runtime/runtime_state.h" +#include "util/arrow/row_batch.h" #include "util/runtime_profile.h" #include "util/telemetry/telemetry.h" #include "vec/exprs/vexpr.h" @@ -98,12 +99,15 @@ Status VResultSink::prepare(RuntimeState* state) { _writer.reset(new (std::nothrow) VMysqlResultWriter(_sender.get(), _output_vexpr_ctxs, _profile)); break; - case TResultSinkType::ARROW_FLIGHT_PROTOCAL: - state->exec_env()->result_mgr()->register_row_descriptor(state->fragment_instance_id(), - _row_desc); + case TResultSinkType::ARROW_FLIGHT_PROTOCAL: { + std::shared_ptr arrow_schema; + RETURN_IF_ERROR(convert_expr_ctxs_arrow_schema(_output_vexpr_ctxs, &arrow_schema)); + state->exec_env()->result_mgr()->register_arrow_schema(state->fragment_instance_id(), + arrow_schema); _writer.reset(new (std::nothrow) VArrowFlightResultWriter(_sender.get(), _output_vexpr_ctxs, - _profile, _row_desc)); + _profile, arrow_schema)); break; + } default: return Status::InternalError("Unknown result sink type"); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java b/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java index 5a4806b12ec3a9..27e61ff87e0588 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/common/ErrorCode.java @@ -1204,7 +1204,10 @@ public enum ErrorCode { "the auto increment must be BIGINT type."), ERR_AUTO_INCREMENT_COLUMN_IN_AGGREGATE_TABLE(5096, new byte[]{'4', '2', '0', '0', '0'}, - "the auto increment is only supported in duplicate table and unique table."); + "the auto increment is only supported in duplicate table and unique table."), + + ERR_ARROW_FLIGHT_SQL_MUST_ONLY_RESULT_STMT(5097, new byte[]{'4', '2', '0', '0', '0'}, + "There can only be one stmt that returns the result and it is at the end."); // This is error code private final int code; diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/AcceptListener.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/AcceptListener.java index 1bde95c165073c..67a84bfb8a2fc7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/AcceptListener.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/AcceptListener.java @@ -22,6 +22,7 @@ import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.ConnectProcessor; import org.apache.doris.qe.ConnectScheduler; +import org.apache.doris.qe.MysqlConnectProcessor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -81,7 +82,7 @@ public void handleEvent(AcceptingChannel channel) { context.getEnv().getAuth().getQueryTimeout(context.getQualifiedUser())); context.setUserInsertTimeout( context.getEnv().getAuth().getInsertTimeout(context.getQualifiedUser())); - ConnectProcessor processor = new ConnectProcessor(context); + ConnectProcessor processor = new MysqlConnectProcessor(context); context.startAcceptQuery(processor); } catch (AfterConnectedException e) { // do not need to print log for this kind of exception. diff --git a/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCommand.java b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCommand.java index f8a03029d5a383..f1f1a44313114d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCommand.java +++ b/fe/fe-core/src/main/java/org/apache/doris/mysql/MysqlCommand.java @@ -23,6 +23,7 @@ import java.util.Map; // MySQL protocol text command +// Reused by arrow flight protocol public enum MysqlCommand { COM_SLEEP("Sleep", 0), COM_QUIT("Quit", 1), diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java index 15359faacaf650..183edb765cd9a9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectContext.java @@ -17,6 +17,7 @@ package org.apache.doris.qe; +import org.apache.doris.analysis.Expr; import org.apache.doris.analysis.UserIdentity; import org.apache.doris.catalog.DatabaseIf; import org.apache.doris.catalog.Env; @@ -39,10 +40,12 @@ import org.apache.doris.nereids.stats.StatsErrorEstimator; import org.apache.doris.plugin.AuditEvent.AuditEventBuilder; import org.apache.doris.resource.Tag; +import org.apache.doris.service.arrowflight.results.FlightSqlChannel; import org.apache.doris.statistics.ColumnStatistic; import org.apache.doris.statistics.Histogram; import org.apache.doris.system.Backend; import org.apache.doris.task.LoadTaskInfo; +import org.apache.doris.thrift.TNetworkAddress; import org.apache.doris.thrift.TResultSinkType; import org.apache.doris.thrift.TUniqueId; import org.apache.doris.transaction.TransactionEntry; @@ -59,6 +62,7 @@ import org.xnio.StreamConnection; import java.io.IOException; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -77,7 +81,7 @@ public class ConnectContext { public enum ConnectType { MYSQL, - ARROW_FLIGHT + ARROW_FLIGHT_SQL } protected volatile ConnectType connectType; @@ -96,8 +100,14 @@ public enum ConnectType { protected volatile int connectionId; // Timestamp when the connection is make protected volatile long loginTime; - // arrow flight token + // for arrow flight protected volatile String peerIdentity; + private String runningQuery; + private TNetworkAddress resultFlightServerAddr; + private TNetworkAddress resultInternalServiceAddr; + private ArrayList resultOutputExprs; + private TUniqueId finstId; + private boolean returnResultFromLocal = true; // mysql net protected volatile MysqlChannel mysqlChannel; // state @@ -190,7 +200,7 @@ public enum ConnectType { private TResultSinkType resultSinkType = TResultSinkType.MYSQL_PROTOCAL; - //internal call like `insert overwrite` need skipAuth + // internal call like `insert overwrite` need skipAuth // For example, `insert overwrite` only requires load permission, // but the internal implementation will call the logic of `AlterTable`. // In this case, `skipAuth` needs to be set to `true` to skip the permission check of `AlterTable` @@ -286,41 +296,30 @@ public ConnectType getConnectType() { return connectType; } - public ConnectContext() { - this((StreamConnection) null); - } - - public ConnectContext(String peerIdentity) { - this.connectType = ConnectType.ARROW_FLIGHT; - this.peerIdentity = peerIdentity; + public void init() { state = new QueryState(); returnRows = 0; isKilled = false; sessionVariable = VariableMgr.newSessionVariable(); - mysqlChannel = new DummyMysqlChannel(); command = MysqlCommand.COM_SLEEP; if (Config.use_fuzzy_session_variable) { sessionVariable.initFuzzyModeVariables(); } - setResultSinkType(TResultSinkType.ARROW_FLIGHT_PROTOCAL); + } + + public ConnectContext() { + this((StreamConnection) null); } public ConnectContext(StreamConnection connection) { connectType = ConnectType.MYSQL; - state = new QueryState(); - returnRows = 0; serverCapability = MysqlCapability.DEFAULT_CAPABILITY; - isKilled = false; if (connection != null) { mysqlChannel = new MysqlChannel(connection); } else { mysqlChannel = new DummyMysqlChannel(); } - sessionVariable = VariableMgr.newSessionVariable(); - command = MysqlCommand.COM_SLEEP; - if (Config.use_fuzzy_session_variable) { - sessionVariable.initFuzzyModeVariables(); - } + init(); } public boolean isTxnModel() { @@ -541,14 +540,70 @@ public void resetLoginTime() { this.loginTime = System.currentTimeMillis(); } + public void setRunningQuery(String runningQuery) { + this.runningQuery = runningQuery; + } + + public String getRunningQuery() { + return runningQuery; + } + + public void setResultFlightServerAddr(TNetworkAddress resultFlightServerAddr) { + this.resultFlightServerAddr = resultFlightServerAddr; + } + + public TNetworkAddress getResultFlightServerAddr() { + return resultFlightServerAddr; + } + + public void setResultInternalServiceAddr(TNetworkAddress resultInternalServiceAddr) { + this.resultInternalServiceAddr = resultInternalServiceAddr; + } + + public TNetworkAddress getResultInternalServiceAddr() { + return resultInternalServiceAddr; + } + + public void setResultOutputExprs(ArrayList resultOutputExprs) { + this.resultOutputExprs = resultOutputExprs; + } + + public ArrayList getResultOutputExprs() { + return resultOutputExprs; + } + + public void setFinstId(TUniqueId finstId) { + this.finstId = finstId; + } + + public TUniqueId getFinstId() { + return finstId; + } + + public void setReturnResultFromLocal(boolean returnResultFromLocal) { + this.returnResultFromLocal = returnResultFromLocal; + } + + public boolean isReturnResultFromLocal() { + return returnResultFromLocal; + } + public String getPeerIdentity() { return peerIdentity; } + public FlightSqlChannel getFlightSqlChannel() { + throw new RuntimeException("getFlightSqlChannel not in flight sql connection"); + } + public MysqlChannel getMysqlChannel() { return mysqlChannel; } + public String getClientIP() { + return getMysqlChannel().getRemoteHostPortString(); + } + public QueryState getState() { return state; } @@ -620,10 +675,14 @@ public StmtExecutor getExecutor() { return executor; } - public void cleanup() { + protected void closeChannel() { if (mysqlChannel != null) { mysqlChannel.close(); } + } + + public void cleanup() { + closeChannel(); threadLocalInfo.remove(); returnRows = 0; } @@ -701,27 +760,17 @@ public void setResultSinkType(TResultSinkType resultSinkType) { } public String getRemoteHostPortString() { - if (connectType.equals(ConnectType.MYSQL)) { - return getMysqlChannel().getRemoteHostPortString(); - } else if (connectType.equals(ConnectType.ARROW_FLIGHT)) { - // TODO Get flight client IP:Port - return peerIdentity; - } - return ""; + return getMysqlChannel().getRemoteHostPortString(); } // kill operation with no protect. public void kill(boolean killConnection) { - LOG.warn("kill query from {}, kill connection: {}", getRemoteHostPortString(), killConnection); + LOG.warn("kill query from {}, kill mysql connection: {}", getRemoteHostPortString(), killConnection); if (killConnection) { isKilled = true; - if (connectType.equals(ConnectType.MYSQL)) { - // Close channel to break connection with client - getMysqlChannel().close(); - } else if (connectType.equals(ConnectType.ARROW_FLIGHT)) { - connectScheduler.unregisterConnection(this); - } + // Close channel to break connection with client + closeChannel(); } // Now, cancel running query. cancelQuery(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java index 5640a8c034c74f..3885af944b2ff9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectProcessor.java @@ -17,11 +17,8 @@ package org.apache.doris.qe; -import org.apache.doris.analysis.ExecuteStmt; import org.apache.doris.analysis.InsertStmt; import org.apache.doris.analysis.KillStmt; -import org.apache.doris.analysis.LiteralExpr; -import org.apache.doris.analysis.NullLiteral; import org.apache.doris.analysis.QueryStmt; import org.apache.doris.analysis.SqlParser; import org.apache.doris.analysis.SqlScanner; @@ -35,7 +32,7 @@ import org.apache.doris.common.AnalysisException; import org.apache.doris.common.DdlException; import org.apache.doris.common.ErrorCode; -import org.apache.doris.common.ErrorReport; +import org.apache.doris.common.NotImplementedException; import org.apache.doris.common.UserException; import org.apache.doris.common.telemetry.Telemetry; import org.apache.doris.common.util.DebugUtil; @@ -47,7 +44,6 @@ import org.apache.doris.mysql.MysqlChannel; import org.apache.doris.mysql.MysqlCommand; import org.apache.doris.mysql.MysqlPacket; -import org.apache.doris.mysql.MysqlProto; import org.apache.doris.mysql.MysqlSerializer; import org.apache.doris.mysql.MysqlServerStatusFlag; import org.apache.doris.nereids.exceptions.NotSupportedException; @@ -61,6 +57,7 @@ import org.apache.doris.thrift.TMasterOpResult; import org.apache.doris.thrift.TUniqueId; +import com.google.common.base.Preconditions; import com.google.common.base.Strings; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.SpanKind; @@ -74,9 +71,6 @@ import java.io.IOException; import java.io.StringReader; import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.channels.AsynchronousCloseException; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -84,11 +78,16 @@ import java.util.UUID; /** - * Process one mysql connection, receive one packet, process, send one packet. + * Process one connection, the life cycle is the same as connection */ -public class ConnectProcessor { +public abstract class ConnectProcessor { + public enum ConnectType { + MYSQL, + ARROW_FLIGHT_SQL + } + private static final Logger LOG = LogManager.getLogger(ConnectProcessor.class); - private static final TextMapGetter> getter = + protected static final TextMapGetter> getter = new TextMapGetter>() { @Override public Iterable keys(Map carrier) { @@ -103,17 +102,17 @@ public String get(Map carrier, String key) { return ""; } }; - private final ConnectContext ctx; - private ByteBuffer packetBuf; - private StmtExecutor executor = null; + protected final ConnectContext ctx; + protected StmtExecutor executor = null; + protected ConnectType connectType; + protected ArrayList returnResultFromRemoteExecutor = new ArrayList<>(); public ConnectProcessor(ConnectContext context) { this.ctx = context; } - // COM_INIT_DB: change current database of this session. - private void handleInitDb() { - String fullDbName = new String(packetBuf.array(), 1, packetBuf.limit() - 1); + // change current database of this session. + protected void handleInitDb(String fullDbName) { if (Strings.isNullOrEmpty(ctx.getClusterName())) { ctx.getState().setError(ErrorCode.ERR_CLUSTER_NAME_NULL, "Please enter cluster"); return; @@ -160,24 +159,22 @@ private void handleInitDb() { ctx.getState().setOk(); } - // COM_QUIT: set killed flag and then return OK packet. - private void handleQuit() { + // set killed flag + protected void handleQuit() { ctx.setKilled(); ctx.getState().setOk(); } - // process COM_PING statement, do nothing, just return one OK packet. - private void handlePing() { + // do nothing + protected void handlePing() { ctx.getState().setOk(); } - private void handleStmtReset() { + protected void handleStmtReset() { ctx.getState().setOk(); } - private void handleStmtClose() { - packetBuf = packetBuf.order(ByteOrder.LITTLE_ENDIAN); - int stmtId = packetBuf.getInt(); + protected void handleStmtClose(int stmtId) { LOG.debug("close stmt id: {}", stmtId); ConnectContext.get().removePrepareStmt(String.valueOf(stmtId)); // No response packet is sent back to the client, see @@ -185,119 +182,27 @@ private void handleStmtClose() { ctx.getState().setNoop(); } - private void debugPacket() { - byte[] bytes = packetBuf.array(); - StringBuilder printB = new StringBuilder(); - for (byte b : bytes) { - if (Character.isLetterOrDigit((char) b & 0xFF)) { - char x = (char) b; - printB.append(x); - } else { - printB.append("0x" + Integer.toHexString(b & 0xFF)); - } - printB.append(" "); - } - LOG.debug("debug packet {}", printB.toString().substring(0, 200)); - } - - private static boolean isNull(byte[] bitmap, int position) { + protected static boolean isNull(byte[] bitmap, int position) { return (bitmap[position / 8] & (1 << (position & 7))) != 0; } - // process COM_EXECUTE, parse binary row data - // https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_execute.html - private void handleExecute() { - // debugPacket(); - packetBuf = packetBuf.order(ByteOrder.LITTLE_ENDIAN); - // parse stmt_id, flags, params - int stmtId = packetBuf.getInt(); - // flag - packetBuf.get(); - // iteration_count always 1, - packetBuf.getInt(); - LOG.debug("execute prepared statement {}", stmtId); - PrepareStmtContext prepareCtx = ctx.getPreparedStmt(String.valueOf(stmtId)); - if (prepareCtx == null) { - LOG.debug("No such statement in context, stmtId:{}", stmtId); - ctx.getState().setError(ErrorCode.ERR_UNKNOWN_COM_ERROR, - "msg: Not supported such prepared statement"); - return; - } - ctx.setStartTime(); - if (prepareCtx.stmt.getInnerStmt() instanceof QueryStmt) { - ctx.getState().setIsQuery(true); - } - prepareCtx.stmt.setIsPrepared(); - int paramCount = prepareCtx.stmt.getParmCount(); - // null bitmap - byte[] nullbitmapData = new byte[(paramCount + 7) / 8]; - packetBuf.get(nullbitmapData); - String stmtStr = ""; - try { - // new_params_bind_flag - if ((int) packetBuf.get() != 0) { - // parse params's types - for (int i = 0; i < paramCount; ++i) { - int typeCode = packetBuf.getChar(); - LOG.debug("code {}", typeCode); - prepareCtx.stmt.placeholders().get(i).setTypeCode(typeCode); - } - } - List realValueExprs = new ArrayList<>(); - // parse param data - for (int i = 0; i < paramCount; ++i) { - if (isNull(nullbitmapData, i)) { - realValueExprs.add(new NullLiteral()); - continue; - } - LiteralExpr l = prepareCtx.stmt.placeholders().get(i).createLiteralFromType(); - l.setupParamFromBinary(packetBuf); - realValueExprs.add(l); - } - ExecuteStmt executeStmt = new ExecuteStmt(String.valueOf(stmtId), realValueExprs); - // TODO set real origin statement - executeStmt.setOrigStmt(new OriginStatement("null", 0)); - executeStmt.setUserInfo(ctx.getCurrentUserIdentity()); - LOG.debug("executeStmt {}", executeStmt); - executor = new StmtExecutor(ctx, executeStmt); - ctx.setExecutor(executor); - executor.execute(); - stmtStr = executeStmt.toSql(); - } catch (Throwable e) { - // Catch all throwable. - // If reach here, maybe palo bug. - LOG.warn("Process one query failed because unknown reason: ", e); - ctx.getState().setError(ErrorCode.ERR_UNKNOWN_ERROR, - e.getClass().getSimpleName() + ", msg: " + e.getMessage()); - } - auditAfterExec(stmtStr, prepareCtx.stmt.getInnerStmt(), null, false); - } - - private void auditAfterExec(String origStmt, StatementBase parsedStmt, - Data.PQueryStatistics statistics, boolean printFuzzyVariables) { + protected void auditAfterExec(String origStmt, StatementBase parsedStmt, + Data.PQueryStatistics statistics, boolean printFuzzyVariables) { AuditLogHelper.logAuditLog(ctx, origStmt, parsedStmt, statistics, printFuzzyVariables); } - // Process COM_QUERY statement, // only throw an exception when there is a problem interacting with the requesting client - private void handleQuery(MysqlCommand mysqlCommand) { + protected void handleQuery(MysqlCommand mysqlCommand, String originStmt) { if (MetricRepo.isInit) { MetricRepo.COUNTER_REQUEST_ALL.increase(1L); } - // convert statement to Java string - byte[] bytes = packetBuf.array(); - int ending = packetBuf.limit() - 1; - while (ending >= 1 && bytes[ending] == '\0') { - ending--; - } - String originStmt = new String(bytes, 1, ending, StandardCharsets.UTF_8); String sqlHash = DigestUtils.md5Hex(originStmt); ctx.setSqlHash(sqlHash); ctx.getAuditEventBuilder().reset(); ctx.getAuditEventBuilder() .setTimestamp(System.currentTimeMillis()) - .setClientIp(ctx.getMysqlChannel().getRemoteHostPortString()) + .setClientIp(ctx.getClientIP()) .setUser(ClusterNamespace.getNameFromFullName(ctx.getQualifiedUser())) .setSqlHash(ctx.getSqlHash()); @@ -356,10 +261,25 @@ private void handleQuery(MysqlCommand mysqlCommand) { try { executor.execute(); - if (i != stmts.size() - 1) { - ctx.getState().serverStatus |= MysqlServerStatusFlag.SERVER_MORE_RESULTS_EXISTS; - if (ctx.getState().getStateType() != MysqlStateType.ERR) { - finalizeCommand(); + if (connectType.equals(ConnectType.MYSQL)) { + if (i != stmts.size() - 1) { + ctx.getState().serverStatus |= MysqlServerStatusFlag.SERVER_MORE_RESULTS_EXISTS; + if (ctx.getState().getStateType() != MysqlStateType.ERR) { + finalizeCommand(); + } + } + } else if (connectType.equals(ConnectType.ARROW_FLIGHT_SQL)) { + if (!ctx.isReturnResultFromLocal()) { + returnResultFromRemoteExecutor.add(executor); + } + Preconditions.checkState(ctx.getFlightSqlChannel().resultNum() <= 1); + if (ctx.getFlightSqlChannel().resultNum() == 1 && i != stmts.size() - 1) { + String errMsg = "Only be one stmt that returns the result and it is at the end. stmts.size(): " + + stmts.size(); + LOG.warn(errMsg); + ctx.getState().setError(ErrorCode.ERR_ARROW_FLIGHT_SQL_MUST_ONLY_RESULT_STMT, errMsg); + ctx.getState().setErrType(QueryState.ErrType.OTHER_ERR); + break; } } auditAfterExec(auditStmt, executor.getParsedStmt(), executor.getQueryStatisticsForAuditLog(), true); @@ -381,8 +301,8 @@ private void handleQuery(MysqlCommand mysqlCommand) { } // Use a handler for exception to avoid big try catch block which is a little hard to understand - private void handleQueryException(Throwable throwable, String origStmt, - StatementBase parsedStmt, Data.PQueryStatistics statistics) { + protected void handleQueryException(Throwable throwable, String origStmt, + StatementBase parsedStmt, Data.PQueryStatistics statistics) { if (ctx.getMinidump() != null) { MinidumpUtils.saveMinidumpString(ctx.getMinidump(), DebugUtil.printId(ctx.queryId())); } @@ -415,7 +335,7 @@ private void handleQueryException(Throwable throwable, String origStmt, } // analyze the origin stmt and return multi-statements - private List parse(String originStmt) throws AnalysisException, DdlException { + protected List parse(String originStmt) throws AnalysisException, DdlException { LOG.debug("the originStmts are: {}", originStmt); // Parse statement with parser generated by CUP&FLEX SqlScanner input = new SqlScanner(new StringReader(originStmt), ctx.getSessionVariable().getSqlMode()); @@ -443,9 +363,8 @@ private List parse(String originStmt) throws AnalysisException, D // Get the column definitions of a table @SuppressWarnings("rawtypes") - private void handleFieldList() throws IOException { + protected void handleFieldList(String tableName) { // Already get command code. - String tableName = new String(MysqlProto.readNulTerminateString(packetBuf), StandardCharsets.UTF_8); if (Strings.isNullOrEmpty(tableName)) { ctx.getState().setError(ErrorCode.ERR_UNKNOWN_TABLE, "Empty tableName"); return; @@ -463,18 +382,21 @@ private void handleFieldList() throws IOException { table.readLock(); try { - MysqlChannel channel = ctx.getMysqlChannel(); - MysqlSerializer serializer = channel.getSerializer(); - - // Send fields - // NOTE: Field list doesn't send number of fields - List baseSchema = table.getBaseSchema(); - for (Column column : baseSchema) { - serializer.reset(); - serializer.writeField(db.getFullName(), table.getName(), column, true); - channel.sendOnePacket(serializer.toByteBuffer()); + if (connectType.equals(ConnectType.MYSQL)) { + MysqlChannel channel = ctx.getMysqlChannel(); + MysqlSerializer serializer = channel.getSerializer(); + + // Send fields + // NOTE: Field list doesn't send number of fields + List baseSchema = table.getBaseSchema(); + for (Column column : baseSchema) { + serializer.reset(); + serializer.writeField(db.getFullName(), table.getName(), column, true); + channel.sendOnePacket(serializer.toByteBuffer()); + } + } else if (connectType.equals(ConnectType.ARROW_FLIGHT_SQL)) { + // TODO } - } catch (Throwable throwable) { handleQueryException(throwable, "", null, null); } finally { @@ -483,62 +405,9 @@ private void handleFieldList() throws IOException { ctx.getState().setEof(); } - private void dispatch() throws IOException { - int code = packetBuf.get(); - MysqlCommand command = MysqlCommand.fromCode(code); - if (command == null) { - ErrorReport.report(ErrorCode.ERR_UNKNOWN_COM_ERROR); - ctx.getState().setError(ErrorCode.ERR_UNKNOWN_COM_ERROR, "Unknown command(" + code + ")"); - LOG.warn("Unknown command(" + code + ")"); - return; - } - LOG.debug("handle command {}", command); - ctx.setCommand(command); - ctx.setStartTime(); - - switch (command) { - case COM_INIT_DB: - handleInitDb(); - break; - case COM_QUIT: - handleQuit(); - break; - case COM_QUERY: - case COM_STMT_PREPARE: - ctx.initTracer("trace"); - Span rootSpan = ctx.getTracer().spanBuilder("handleQuery").setNoParent().startSpan(); - try (Scope scope = rootSpan.makeCurrent()) { - handleQuery(command); - } catch (Exception e) { - rootSpan.recordException(e); - throw e; - } finally { - rootSpan.end(); - } - break; - case COM_STMT_EXECUTE: - handleExecute(); - break; - case COM_FIELD_LIST: - handleFieldList(); - break; - case COM_PING: - handlePing(); - break; - case COM_STMT_RESET: - handleStmtReset(); - break; - case COM_STMT_CLOSE: - handleStmtClose(); - break; - default: - ctx.getState().setError(ErrorCode.ERR_UNKNOWN_COM_ERROR, "Unsupported command(" + command + ")"); - LOG.warn("Unsupported command(" + command + ")"); - break; - } - } - - private ByteBuffer getResultPacket() { + // only Mysql protocol + protected ByteBuffer getResultPacket() { + Preconditions.checkState(connectType.equals(ConnectType.MYSQL)); MysqlPacket packet = ctx.getState().toResponsePacket(); if (packet == null) { // possible two cases: @@ -555,7 +424,9 @@ private ByteBuffer getResultPacket() { // When any request is completed, it will generally need to send a response packet to the client // This method is used to send a response packet to the client - private void finalizeCommand() throws IOException { + // only Mysql protocol + public void finalizeCommand() throws IOException { + Preconditions.checkState(connectType.equals(ConnectType.MYSQL)); ByteBuffer packet; if (executor != null && executor.isForwardToMaster() && ctx.getState().getStateType() != QueryState.MysqlStateType.ERR) { @@ -736,47 +607,9 @@ public TMasterOpResult proxyExecute(TMasterOpRequest request) { return result; } - // Process a MySQL request - public void processOnce() throws IOException { - // set status of query to OK. - ctx.getState().reset(); - executor = null; - - // reset sequence id of MySQL protocol - final MysqlChannel channel = ctx.getMysqlChannel(); - channel.setSequenceId(0); - // read packet from channel - try { - packetBuf = channel.fetchOnePacket(); - if (packetBuf == null) { - LOG.warn("Null packet received from network. remote: {}", channel.getRemoteHostPortString()); - throw new IOException("Error happened when receiving packet."); - } - } catch (AsynchronousCloseException e) { - // when this happened, timeout checker close this channel - // killed flag in ctx has been already set, just return - return; - } - - // dispatch - dispatch(); - // finalize - finalizeCommand(); - - ctx.setCommand(MysqlCommand.COM_SLEEP); - } - - public void loop() { - while (!ctx.isKilled()) { - try { - processOnce(); - } catch (Exception e) { - // TODO(zhaochun): something wrong - LOG.warn("Exception happened in one session(" + ctx + ").", e); - ctx.setKilled(); - break; - } - } + // only Mysql protocol + public void processOnce() throws IOException, NotImplementedException { + throw new NotImplementedException("Not Impl processOnce"); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java index 70bfd7e2d8cdd9..5be4c330e0aec2 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/ConnectScheduler.java @@ -102,7 +102,7 @@ public boolean registerConnection(ConnectContext ctx) { return false; } connectionMap.put(ctx.getConnectionId(), ctx); - if (ctx.getConnectType().equals(ConnectType.ARROW_FLIGHT)) { + if (ctx.getConnectType().equals(ConnectType.ARROW_FLIGHT_SQL)) { flightToken2ConnectionId.put(ctx.getPeerIdentity(), ctx.getConnectionId()); } return true; @@ -116,7 +116,7 @@ public void unregisterConnection(ConnectContext ctx) { conns.decrementAndGet(); } numberConnection.decrementAndGet(); - if (ctx.getConnectType().equals(ConnectType.ARROW_FLIGHT)) { + if (ctx.getConnectType().equals(ConnectType.ARROW_FLIGHT_SQL)) { flightToken2ConnectionId.remove(ctx.getPeerIdentity()); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java index 752dedf8015495..9aaca2f8e2cdbb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java @@ -19,7 +19,6 @@ import org.apache.doris.analysis.Analyzer; import org.apache.doris.analysis.DescriptorTable; -import org.apache.doris.analysis.Expr; import org.apache.doris.analysis.StorageBackend; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.FsBroker; @@ -68,6 +67,7 @@ import org.apache.doris.proto.InternalService.PExecPlanFragmentStartRequest; import org.apache.doris.proto.Types; import org.apache.doris.proto.Types.PUniqueId; +import org.apache.doris.qe.ConnectContext.ConnectType; import org.apache.doris.qe.QueryStatisticsItem.FragmentInstanceInfo; import org.apache.doris.rpc.BackendServiceProxy; import org.apache.doris.rpc.RpcException; @@ -210,11 +210,6 @@ public class Coordinator implements CoordInterface { private final List needCheckBackendExecStates = Lists.newArrayList(); private final List needCheckPipelineExecContexts = Lists.newArrayList(); private ResultReceiver receiver; - private TNetworkAddress resultFlightServerAddr; - private TNetworkAddress resultInternalServiceAddr; - private ArrayList resultOutputExprs; - - private TUniqueId finstId; private final List scanNodes; private int scanRangeNum = 0; // number of instances of this query, equals to @@ -283,22 +278,6 @@ public ExecutionProfile getExecutionProfile() { return executionProfile; } - public TNetworkAddress getResultFlightServerAddr() { - return resultFlightServerAddr; - } - - public TNetworkAddress getResultInternalServiceAddr() { - return resultInternalServiceAddr; - } - - public ArrayList getResultOutputExprs() { - return resultOutputExprs; - } - - public TUniqueId getFinstId() { - return finstId; - } - // True if all scan node are ExternalScanNode. private boolean isAllExternalScan = true; @@ -631,10 +610,14 @@ public void exec() throws Exception { TNetworkAddress execBeAddr = topParams.instanceExecParams.get(0).host; receiver = new ResultReceiver(queryId, topParams.instanceExecParams.get(0).instanceId, addressToBackendID.get(execBeAddr), toBrpcHost(execBeAddr), this.timeoutDeadline); - finstId = topParams.instanceExecParams.get(0).instanceId; - resultFlightServerAddr = toArrowFlightHost(execBeAddr); - resultInternalServiceAddr = toBrpcHost(execBeAddr); - resultOutputExprs = fragments.get(0).getOutputExprs(); + + if (!context.isReturnResultFromLocal()) { + Preconditions.checkState(context.getConnectType().equals(ConnectType.ARROW_FLIGHT_SQL)); + context.setFinstId(topParams.instanceExecParams.get(0).instanceId); + context.setResultFlightServerAddr(toArrowFlightHost(execBeAddr)); + context.setResultInternalServiceAddr(toBrpcHost(execBeAddr)); + context.setResultOutputExprs(fragments.get(0).getOutputExprs()); + } if (LOG.isDebugEnabled()) { LOG.debug("dispatch result sink of query {} to {}", DebugUtil.printId(queryId), topParams.instanceExecParams.get(0).host); diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/MysqlConnectProcessor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/MysqlConnectProcessor.java new file mode 100644 index 00000000000000..63781d2addaff5 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/MysqlConnectProcessor.java @@ -0,0 +1,272 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.qe; + +import org.apache.doris.analysis.ExecuteStmt; +import org.apache.doris.analysis.LiteralExpr; +import org.apache.doris.analysis.NullLiteral; +import org.apache.doris.analysis.QueryStmt; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; +import org.apache.doris.mysql.MysqlChannel; +import org.apache.doris.mysql.MysqlCommand; +import org.apache.doris.mysql.MysqlProto; + +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Scope; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.AsynchronousCloseException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; + +/** + * Process one mysql connection, receive one packet, process, send one packet. + */ +public class MysqlConnectProcessor extends ConnectProcessor { + private static final Logger LOG = LogManager.getLogger(MysqlConnectProcessor.class); + + private ByteBuffer packetBuf; + + public MysqlConnectProcessor(ConnectContext context) { + super(context); + connectType = ConnectType.MYSQL; + } + + // COM_INIT_DB: change current database of this session. + private void handleInitDb() { + String fullDbName = new String(packetBuf.array(), 1, packetBuf.limit() - 1); + handleInitDb(fullDbName); + } + + private void handleStmtClose() { + packetBuf = packetBuf.order(ByteOrder.LITTLE_ENDIAN); + int stmtId = packetBuf.getInt(); + handleStmtClose(stmtId); + } + + private void debugPacket() { + byte[] bytes = packetBuf.array(); + StringBuilder printB = new StringBuilder(); + for (byte b : bytes) { + if (Character.isLetterOrDigit((char) b & 0xFF)) { + char x = (char) b; + printB.append(x); + } else { + printB.append("0x" + Integer.toHexString(b & 0xFF)); + } + printB.append(" "); + } + LOG.debug("debug packet {}", printB.toString().substring(0, 200)); + } + + // process COM_EXECUTE, parse binary row data + // https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_execute.html + private void handleExecute() { + // debugPacket(); + packetBuf = packetBuf.order(ByteOrder.LITTLE_ENDIAN); + // parse stmt_id, flags, params + int stmtId = packetBuf.getInt(); + // flag + packetBuf.get(); + // iteration_count always 1, + packetBuf.getInt(); + LOG.debug("execute prepared statement {}", stmtId); + PrepareStmtContext prepareCtx = ctx.getPreparedStmt(String.valueOf(stmtId)); + if (prepareCtx == null) { + LOG.debug("No such statement in context, stmtId:{}", stmtId); + ctx.getState().setError(ErrorCode.ERR_UNKNOWN_COM_ERROR, + "msg: Not supported such prepared statement"); + return; + } + ctx.setStartTime(); + if (prepareCtx.stmt.getInnerStmt() instanceof QueryStmt) { + ctx.getState().setIsQuery(true); + } + prepareCtx.stmt.setIsPrepared(); + int paramCount = prepareCtx.stmt.getParmCount(); + // null bitmap + byte[] nullbitmapData = new byte[(paramCount + 7) / 8]; + packetBuf.get(nullbitmapData); + String stmtStr = ""; + try { + // new_params_bind_flag + if ((int) packetBuf.get() != 0) { + // parse params's types + for (int i = 0; i < paramCount; ++i) { + int typeCode = packetBuf.getChar(); + LOG.debug("code {}", typeCode); + prepareCtx.stmt.placeholders().get(i).setTypeCode(typeCode); + } + } + List realValueExprs = new ArrayList<>(); + // parse param data + for (int i = 0; i < paramCount; ++i) { + if (isNull(nullbitmapData, i)) { + realValueExprs.add(new NullLiteral()); + continue; + } + LiteralExpr l = prepareCtx.stmt.placeholders().get(i).createLiteralFromType(); + l.setupParamFromBinary(packetBuf); + realValueExprs.add(l); + } + ExecuteStmt executeStmt = new ExecuteStmt(String.valueOf(stmtId), realValueExprs); + // TODO set real origin statement + executeStmt.setOrigStmt(new OriginStatement("null", 0)); + executeStmt.setUserInfo(ctx.getCurrentUserIdentity()); + LOG.debug("executeStmt {}", executeStmt); + executor = new StmtExecutor(ctx, executeStmt); + ctx.setExecutor(executor); + executor.execute(); + stmtStr = executeStmt.toSql(); + } catch (Throwable e) { + // Catch all throwable. + // If reach here, maybe palo bug. + LOG.warn("Process one query failed because unknown reason: ", e); + ctx.getState().setError(ErrorCode.ERR_UNKNOWN_ERROR, + e.getClass().getSimpleName() + ", msg: " + e.getMessage()); + } + auditAfterExec(stmtStr, prepareCtx.stmt.getInnerStmt(), null, false); + } + + // Process COM_QUERY statement, + private void handleQuery(MysqlCommand mysqlCommand) { + // convert statement to Java string + byte[] bytes = packetBuf.array(); + int ending = packetBuf.limit() - 1; + while (ending >= 1 && bytes[ending] == '\0') { + ending--; + } + String originStmt = new String(bytes, 1, ending, StandardCharsets.UTF_8); + + handleQuery(mysqlCommand, originStmt); + } + + private void dispatch() throws IOException { + int code = packetBuf.get(); + MysqlCommand command = MysqlCommand.fromCode(code); + if (command == null) { + ErrorReport.report(ErrorCode.ERR_UNKNOWN_COM_ERROR); + ctx.getState().setError(ErrorCode.ERR_UNKNOWN_COM_ERROR, "Unknown command(" + code + ")"); + LOG.warn("Unknown command(" + code + ")"); + return; + } + LOG.debug("handle command {}", command); + ctx.setCommand(command); + ctx.setStartTime(); + + switch (command) { + case COM_INIT_DB: + handleInitDb(); + break; + case COM_QUIT: + // COM_QUIT: set killed flag and then return OK packet. + handleQuit(); + break; + case COM_QUERY: + case COM_STMT_PREPARE: + // Process COM_QUERY statement, + ctx.initTracer("trace"); + Span rootSpan = ctx.getTracer().spanBuilder("handleQuery").setNoParent().startSpan(); + try (Scope scope = rootSpan.makeCurrent()) { + handleQuery(command); + } catch (Exception e) { + rootSpan.recordException(e); + throw e; + } finally { + rootSpan.end(); + } + break; + case COM_STMT_EXECUTE: + handleExecute(); + break; + case COM_FIELD_LIST: + handleFieldList(); + break; + case COM_PING: + // process COM_PING statement, do nothing, just return one OK packet. + handlePing(); + break; + case COM_STMT_RESET: + handleStmtReset(); + break; + case COM_STMT_CLOSE: + handleStmtClose(); + break; + default: + ctx.getState().setError(ErrorCode.ERR_UNKNOWN_COM_ERROR, "Unsupported command(" + command + ")"); + LOG.warn("Unsupported command(" + command + ")"); + break; + } + } + + private void handleFieldList() { + String tableName = new String(MysqlProto.readNulTerminateString(packetBuf), StandardCharsets.UTF_8); + handleFieldList(tableName); + } + + // Process a MySQL request + public void processOnce() throws IOException { + // set status of query to OK. + ctx.getState().reset(); + executor = null; + + // reset sequence id of MySQL protocol + final MysqlChannel channel = ctx.getMysqlChannel(); + channel.setSequenceId(0); + // read packet from channel + try { + packetBuf = channel.fetchOnePacket(); + if (packetBuf == null) { + LOG.warn("Null packet received from network. remote: {}", channel.getRemoteHostPortString()); + throw new IOException("Error happened when receiving packet."); + } + } catch (AsynchronousCloseException e) { + // when this happened, timeout checker close this channel + // killed flag in ctx has been already set, just return + return; + } + + // dispatch + dispatch(); + // finalize + finalizeCommand(); + + ctx.setCommand(MysqlCommand.COM_SLEEP); + } + + public void loop() { + while (!ctx.isKilled()) { + try { + processOnce(); + } catch (Exception e) { + // TODO(zhaochun): something wrong + LOG.warn("Exception happened in one session(" + ctx + ").", e); + ctx.setKilled(); + break; + } + } + } +} + + diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/QueryState.java b/fe/fe-core/src/main/java/org/apache/doris/qe/QueryState.java index 3619a15876bc7f..a5f52f26288c44 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/QueryState.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/QueryState.java @@ -25,6 +25,7 @@ // query state used to record state of query, maybe query status is better public class QueryState { + // Reused by arrow flight protocol public enum MysqlStateType { NOOP, // send nothing to remote OK, // send OK packet to remote diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java index ec3a5a79586644..8eaff7fdf107cf 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java @@ -136,6 +136,7 @@ import org.apache.doris.proto.InternalService.PGroupCommitInsertResponse; import org.apache.doris.proto.Types; import org.apache.doris.qe.CommonResultSet.CommonResultSetMetaData; +import org.apache.doris.qe.ConnectContext.ConnectType; import org.apache.doris.qe.QueryState.MysqlStateType; import org.apache.doris.qe.cache.Cache; import org.apache.doris.qe.cache.CacheAnalyzer; @@ -147,7 +148,6 @@ import org.apache.doris.rpc.BackendServiceProxy; import org.apache.doris.rpc.RpcException; import org.apache.doris.service.FrontendOptions; -import org.apache.doris.service.arrowflight.FlightStatementExecutor; import org.apache.doris.statistics.ResultRow; import org.apache.doris.statistics.util.InternalQueryBuffer; import org.apache.doris.system.Backend; @@ -242,6 +242,7 @@ public class StmtExecutor { // this constructor is mainly for proxy public StmtExecutor(ConnectContext context, OriginStatement originStmt, boolean isProxy) { + Preconditions.checkState(context.getConnectType().equals(ConnectType.MYSQL)); this.context = context; this.originStmt = originStmt; this.serializer = context.getMysqlChannel().getSerializer(); @@ -262,7 +263,11 @@ public StmtExecutor(ConnectContext ctx, StatementBase parsedStmt) { this.context = ctx; this.parsedStmt = parsedStmt; this.originStmt = parsedStmt.getOrigStmt(); - this.serializer = context.getMysqlChannel().getSerializer(); + if (context.getConnectType() == ConnectType.MYSQL) { + this.serializer = context.getMysqlChannel().getSerializer(); + } else { + this.serializer = null; + } this.isProxy = false; if (parsedStmt instanceof LogicalPlanAdapter) { this.statementContext = ((LogicalPlanAdapter) parsedStmt).getStatementContext(); @@ -428,7 +433,7 @@ public boolean isAnalyzeStmt() { * isValuesOrConstantSelect: when this interface return true, original string is truncated at 1024 * * @return parsed and analyzed statement for Stale planner. - * an unresolved LogicalPlan wrapped with a LogicalPlanAdapter for Nereids. + * an unresolved LogicalPlan wrapped with a LogicalPlanAdapter for Nereids. */ public StatementBase getParsedStmt() { return parsedStmt; @@ -444,13 +449,16 @@ public void execute() throws Exception { public void execute(TUniqueId queryId) throws Exception { SessionVariable sessionVariable = context.getSessionVariable(); Span executeSpan = context.getTracer().spanBuilder("execute").setParent(Context.current()).startSpan(); + if (context.getConnectType() == ConnectType.ARROW_FLIGHT_SQL) { + context.setReturnResultFromLocal(true); + } try (Scope scope = executeSpan.makeCurrent()) { if (parsedStmt instanceof LogicalPlanAdapter || (parsedStmt == null && sessionVariable.isEnableNereidsPlanner())) { try { executeByNereids(queryId); } catch (NereidsException | ParseException e) { - if (context.getMinidump() != null) { + if (context.getMinidump() != null && context.getMinidump().toString(4) != null) { MinidumpUtils.saveMinidumpString(context.getMinidump(), DebugUtil.printId(context.queryId())); } // try to fall back to legacy planner @@ -600,12 +608,23 @@ private void parseByNereids() { } if (statements.size() <= originStmt.idx) { throw new ParseException("Nereids parse failed. Parser get " + statements.size() + " statements," - + " but we need at least " + originStmt.idx + " statements."); + + " but we need at least " + originStmt.idx + " statements."); } parsedStmt = statements.get(originStmt.idx); } + public void finalizeQuery() { + // The final profile report occurs after be returns the query data, and the profile cannot be + // received after unregisterQuery(), causing the instance profile to be lost, so we should wait + // for the profile before unregisterQuery(). + updateProfile(true); + QeProcessorImpl.INSTANCE.unregisterQuery(context.queryId()); + } + private void handleQueryWithRetry(TUniqueId queryId) throws Exception { + if (context.getConnectType() == ConnectType.ARROW_FLIGHT_SQL) { + context.setReturnResultFromLocal(false); + } // queue query here syncJournalIfNeeded(); QueueOfferToken offerRet = null; @@ -631,7 +650,7 @@ private void handleQueryWithRetry(TUniqueId queryId) throws Exception { try { for (int i = 0; i < retryTime; i++) { try { - //reset query id for each retry + // reset query id for each retry if (i > 0) { UUID uuid = UUID.randomUUID(); TUniqueId newQueryId = new TUniqueId(uuid.getMostSignificantBits(), @@ -646,17 +665,15 @@ private void handleQueryWithRetry(TUniqueId queryId) throws Exception { if (i == retryTime - 1) { throw e; } - if (!context.getMysqlChannel().isSend()) { + if (context.getConnectType().equals(ConnectType.MYSQL) && !context.getMysqlChannel().isSend()) { LOG.warn("retry {} times. stmt: {}", (i + 1), parsedStmt.getOrigStmt().originStmt); } else { throw e; } } finally { - // The final profile report occurs after be returns the query data, and the profile cannot be - // received after unregisterQuery(), causing the instance profile to be lost, so we should wait - // for the profile before unregisterQuery(). - updateProfile(true); - QeProcessorImpl.INSTANCE.unregisterQuery(context.queryId()); + if (context.isReturnResultFromLocal()) { + finalizeQuery(); + } } } } finally { @@ -1361,9 +1378,11 @@ private void handleCacheStmt(CacheAnalyzer cacheAnalyzer, MysqlChannel channel) // Process a select statement. private void handleQueryStmt() throws Exception { LOG.info("Handling query {} with query id {}", - originStmt.originStmt, DebugUtil.printId(context.queryId)); - // Every time set no send flag and clean all data in buffer - context.getMysqlChannel().reset(); + originStmt.originStmt, DebugUtil.printId(context.queryId)); + if (context.getConnectType() == ConnectType.MYSQL) { + // Every time set no send flag and clean all data in buffer + context.getMysqlChannel().reset(); + } Queriable queryStmt = (Queriable) parsedStmt; QueryDetail queryDetail = new QueryDetail(context.getStartTime(), @@ -1390,12 +1409,16 @@ private void handleQueryStmt() throws Exception { return; } - MysqlChannel channel = context.getMysqlChannel(); + MysqlChannel channel = null; + if (context.getConnectType().equals(ConnectType.MYSQL)) { + channel = context.getMysqlChannel(); + } boolean isOutfileQuery = queryStmt.hasOutFileClause(); // Sql and PartitionCache CacheAnalyzer cacheAnalyzer = new CacheAnalyzer(context, parsedStmt, planner); - if (cacheAnalyzer.enableCache() && !isOutfileQuery + // TODO support arrow flight sql + if (channel != null && cacheAnalyzer.enableCache() && !isOutfileQuery && context.getSessionVariable().getSqlSelectLimit() < 0 && context.getSessionVariable().getDefaultOrderByLimit() < 0) { if (queryStmt instanceof QueryStmt || queryStmt instanceof LogicalPlanAdapter) { @@ -1406,7 +1429,8 @@ private void handleQueryStmt() throws Exception { } // handle select .. from xx limit 0 - if (parsedStmt instanceof SelectStmt) { + // TODO support arrow flight sql + if (channel != null && parsedStmt instanceof SelectStmt) { SelectStmt parsedSelectStmt = (SelectStmt) parsedStmt; if (parsedSelectStmt.getLimit() == 0) { LOG.info("ignore handle limit 0 ,sql:{}", parsedSelectStmt.toSql()); @@ -1469,6 +1493,22 @@ private void sendResult(boolean isOutfileQuery, boolean isSendFields, Queriable } } + if (context.getConnectType().equals(ConnectType.ARROW_FLIGHT_SQL)) { + Preconditions.checkState(!context.isReturnResultFromLocal()); + profile.getSummaryProfile().setTempStartTime(); + if (coordBase.getInstanceTotalNum() > 1 && LOG.isDebugEnabled()) { + try { + LOG.debug("Finish to execute fragment. user: {}, db: {}, sql: {}, fragment instance num: {}", + context.getQualifiedUser(), context.getDatabase(), + parsedStmt.getOrigStmt().originStmt.replace("\n", " "), + coordBase.getInstanceTotalNum()); + } catch (Exception e) { + LOG.warn("Fail to print fragment concurrency for Query.", e); + } + } + return; + } + Span fetchResultSpan = context.getTracer().spanBuilder("fetch result").setParent(Context.current()).startSpan(); try (Scope scope = fetchResultSpan.makeCurrent()) { while (true) { @@ -1573,8 +1613,10 @@ private TWaitingTxnStatusResult getWaitingTxnStatus(TWaitingTxnStatusRequest req } private void handleTransactionStmt() throws Exception { - // Every time set no send flag and clean all data in buffer - context.getMysqlChannel().reset(); + if (context.getConnectType() == ConnectType.MYSQL) { + // Every time set no send flag and clean all data in buffer + context.getMysqlChannel().reset(); + } context.getState().setOk(0, 0, ""); // create plan if (context.getTxnEntry() != null && context.getTxnEntry().getRowsInTransaction() == 0 @@ -1774,8 +1816,8 @@ private void beginTxn(String dbName, String tblName) throws UserException, TExce // Process an insert statement. private void handleInsertStmt() throws Exception { - // Every time set no send flag and clean all data in buffer - if (context.getMysqlChannel() != null) { + if (context.getConnectType() == ConnectType.MYSQL) { + // Every time set no send flag and clean all data in buffer context.getMysqlChannel().reset(); } InsertStmt insertStmt = (InsertStmt) parsedStmt; @@ -1989,8 +2031,7 @@ private void handleInsertStmt() throws Exception { */ throwable = t; } finally { - updateProfile(true); - QeProcessorImpl.INSTANCE.unregisterQuery(context.queryId()); + finalizeQuery(); } // Go here, which means: @@ -2059,7 +2100,9 @@ private void handleExternalInsertStmt() { } private void handleUnsupportedStmt() { - context.getMysqlChannel().reset(); + if (context.getConnectType() == ConnectType.MYSQL) { + context.getMysqlChannel().reset(); + } // do nothing context.getState().setOk(); } @@ -2084,10 +2127,10 @@ private void handleSwitchStmt() throws AnalysisException { private void handlePrepareStmt() throws Exception { // register prepareStmt LOG.debug("add prepared statement {}, isBinaryProtocol {}", - prepareStmt.getName(), prepareStmt.isBinaryProtocol()); + prepareStmt.getName(), prepareStmt.isBinaryProtocol()); context.addPreparedStmt(prepareStmt.getName(), new PrepareStmtContext(prepareStmt, - context, planner, analyzer, prepareStmt.getName())); + context, planner, analyzer, prepareStmt.getName())); if (prepareStmt.isBinaryProtocol()) { sendStmtPrepareOK(); } @@ -2114,6 +2157,7 @@ private void handleUseStmt() throws AnalysisException { } private void sendMetaData(ResultSetMetaData metaData) throws IOException { + Preconditions.checkState(context.getConnectType() == ConnectType.MYSQL); // sends how many columns serializer.reset(); serializer.writeVInt(metaData.getColumnCount()); @@ -2137,6 +2181,7 @@ private List exprToStringType(List exprs) { } private void sendStmtPrepareOK() throws IOException { + Preconditions.checkState(context.getConnectType() == ConnectType.MYSQL); // https://dev.mysql.com/doc/dev/mysql-server/latest/page_protocol_com_stmt_prepare.html#sect_protocol_com_stmt_prepare_response serializer.reset(); // 0x00 OK @@ -2174,6 +2219,7 @@ private void sendStmtPrepareOK() throws IOException { } private void sendFields(List colNames, List types) throws IOException { + Preconditions.checkState(context.getConnectType() == ConnectType.MYSQL); // sends how many columns serializer.reset(); serializer.writeVInt(colNames.size()); @@ -2205,24 +2251,33 @@ private void sendFields(List colNames, List types) throws IOExcept } public void sendResultSet(ResultSet resultSet) throws IOException { - context.updateReturnRows(resultSet.getResultRows().size()); - // Send meta data. - sendMetaData(resultSet.getMetaData()); + if (context.getConnectType().equals(ConnectType.MYSQL)) { + context.updateReturnRows(resultSet.getResultRows().size()); + // Send meta data. + sendMetaData(resultSet.getMetaData()); - // Send result set. - for (List row : resultSet.getResultRows()) { - serializer.reset(); - for (String item : row) { - if (item == null || item.equals(FeConstants.null_string)) { - serializer.writeNull(); - } else { - serializer.writeLenEncodedString(item); + // Send result set. + for (List row : resultSet.getResultRows()) { + serializer.reset(); + for (String item : row) { + if (item == null || item.equals(FeConstants.null_string)) { + serializer.writeNull(); + } else { + serializer.writeLenEncodedString(item); + } } + context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer()); } - context.getMysqlChannel().sendOnePacket(serializer.toByteBuffer()); - } - context.getState().setEof(); + context.getState().setEof(); + } else if (context.getConnectType().equals(ConnectType.ARROW_FLIGHT_SQL)) { + context.updateReturnRows(resultSet.getResultRows().size()); + context.getFlightSqlChannel() + .addResult(DebugUtil.printId(context.queryId()), context.getRunningQuery(), resultSet); + context.getState().setEof(); + } else { + LOG.error("sendResultSet error connect type"); + } } // Process show statement @@ -2248,6 +2303,7 @@ private void handleLockTablesStmt() { } public void handleExplainStmt(String result, boolean isNereids) throws IOException { + // TODO support arrow flight sql ShowResultSetMetaData metaData = ShowResultSetMetaData.builder() .addColumn(new Column("Explain String" + (isNereids ? "(Nereids Planner)" : "(Old Planner)"), ScalarType.createVarchar(20))) @@ -2686,64 +2742,6 @@ public List executeInternalQuery() { } } - public void executeArrowFlightQuery(FlightStatementExecutor flightStatementExecutor) { - LOG.debug("ARROW FLIGHT QUERY: " + originStmt.toString()); - try { - try { - if (ConnectContext.get() != null - && ConnectContext.get().getSessionVariable().isEnableNereidsPlanner()) { - try { - parseByNereids(); - Preconditions.checkState(parsedStmt instanceof LogicalPlanAdapter, - "Nereids only process LogicalPlanAdapter," - + " but parsedStmt is " + parsedStmt.getClass().getName()); - context.getState().setNereids(true); - context.getState().setIsQuery(true); - planner = new NereidsPlanner(statementContext); - planner.plan(parsedStmt, context.getSessionVariable().toThrift()); - } catch (Exception e) { - LOG.warn("fall back to legacy planner, because: {}", e.getMessage(), e); - parsedStmt = null; - context.getState().setNereids(false); - analyzer = new Analyzer(context.getEnv(), context); - analyze(context.getSessionVariable().toThrift()); - } - } else { - analyzer = new Analyzer(context.getEnv(), context); - analyze(context.getSessionVariable().toThrift()); - } - } catch (Exception e) { - throw new RuntimeException("Failed to execute Arrow Flight SQL. " + Util.getRootCauseMessage(e), e); - } - coord = new Coordinator(context, analyzer, planner, context.getStatsErrorEstimator()); - profile.addExecutionProfile(coord.getExecutionProfile()); - try { - QeProcessorImpl.INSTANCE.registerQuery(context.queryId(), - new QeProcessorImpl.QueryInfo(context, originStmt.originStmt, coord)); - } catch (UserException e) { - throw new RuntimeException("Failed to execute Arrow Flight SQL. " + Util.getRootCauseMessage(e), e); - } - - Span queryScheduleSpan = context.getTracer() - .spanBuilder("Arrow Flight SQL schedule").setParent(Context.current()).startSpan(); - try (Scope scope = queryScheduleSpan.makeCurrent()) { - coord.exec(); - } catch (Exception e) { - queryScheduleSpan.recordException(e); - LOG.warn("Failed to coord exec Arrow Flight SQL, because: {}", e.getMessage(), e); - throw new RuntimeException(e.getMessage() + Util.getRootCauseMessage(e), e); - } finally { - queryScheduleSpan.end(); - } - } finally { - QeProcessorImpl.INSTANCE.unregisterQuery(context.queryId()); // TODO for query profile - } - flightStatementExecutor.setFinstId(coord.getFinstId()); - flightStatementExecutor.setResultFlightServerAddr(coord.getResultFlightServerAddr()); - flightStatementExecutor.setResultInternalServiceAddr(coord.getResultInternalServiceAddr()); - flightStatementExecutor.setResultOutputExprs(coord.getResultOutputExprs()); - } - private List convertResultBatchToResultRows(TResultBatch batch) { List columns = parsedStmt.getColLabels(); List resultRows = new ArrayList<>(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java index 514b9df525dc7f..6ef0956808be1f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java +++ b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java @@ -83,15 +83,18 @@ import org.apache.doris.planner.OlapTableSink; import org.apache.doris.planner.StreamLoadPlanner; import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.ConnectContext.ConnectType; import org.apache.doris.qe.ConnectProcessor; import org.apache.doris.qe.Coordinator; import org.apache.doris.qe.DdlExecutor; import org.apache.doris.qe.MasterCatalogExecutor; +import org.apache.doris.qe.MysqlConnectProcessor; import org.apache.doris.qe.OriginStatement; import org.apache.doris.qe.QeProcessorImpl; import org.apache.doris.qe.QueryState; import org.apache.doris.qe.StmtExecutor; import org.apache.doris.qe.VariableMgr; +import org.apache.doris.service.arrowflight.FlightSqlConnectProcessor; import org.apache.doris.statistics.ColumnStatistic; import org.apache.doris.statistics.ResultRow; import org.apache.doris.statistics.StatisticsCacheKey; @@ -1104,7 +1107,16 @@ public TMasterOpResult forward(TMasterOpRequest params) throws TException { ConnectContext context = new ConnectContext(); // Set current connected FE to the client address, so that we can know where this request come from. context.setCurrentConnectedFEIp(params.getClientNodeHost()); - ConnectProcessor processor = new ConnectProcessor(context); + + ConnectProcessor processor = null; + if (context.getConnectType().equals(ConnectType.MYSQL)) { + processor = new MysqlConnectProcessor(context); + } else if (context.getConnectType().equals(ConnectType.ARROW_FLIGHT_SQL)) { + processor = new FlightSqlConnectProcessor(context); + } else { + throw new TException("unknown ConnectType: " + context.getConnectType()); + } + TMasterOpResult result = processor.proxyExecute(params); if (QueryState.MysqlStateType.ERR.name().equalsIgnoreCase(result.getStatus())) { context.getState().setError(result.getStatus()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/DorisFlightSqlProducer.java b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/DorisFlightSqlProducer.java index 0e73fbb2ad69bd..d2f8b46b893683 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/DorisFlightSqlProducer.java +++ b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/DorisFlightSqlProducer.java @@ -24,8 +24,11 @@ import org.apache.doris.common.util.Util; import org.apache.doris.mysql.MysqlCommand; import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.QueryState.MysqlStateType; +import org.apache.doris.service.arrowflight.results.FlightSqlResultCacheEntry; import org.apache.doris.service.arrowflight.sessions.FlightSessionsManager; +import com.google.common.base.Preconditions; import com.google.protobuf.Any; import com.google.protobuf.ByteString; import com.google.protobuf.Message; @@ -63,12 +66,15 @@ import org.apache.arrow.memory.BufferAllocator; import org.apache.arrow.memory.RootAllocator; import org.apache.arrow.util.AutoCloseables; +import org.apache.arrow.vector.VectorSchemaRoot; import org.apache.arrow.vector.types.pojo.Schema; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.UUID; public class DorisFlightSqlProducer implements FlightSqlProducer, AutoCloseable { private static final Logger LOG = LogManager.getLogger(DorisFlightSqlProducer.class); @@ -111,33 +117,72 @@ public FlightInfo getFlightInfoStatement(final CommandStatementQuery request, fi ConnectContext connectContext = null; try { connectContext = flightSessionsManager.getConnectContext(context.peerIdentity()); - // Only for ConnectContext check timeout. - connectContext.setCommand(MysqlCommand.COM_QUERY); + // After the previous query was executed, there was no getStreamStatement to take away the result. + connectContext.getFlightSqlChannel().reset(); final String query = request.getQuery(); - final FlightStatementExecutor flightStatementExecutor = new FlightStatementExecutor(query, connectContext); - - flightStatementExecutor.executeQuery(); - - TicketStatementQuery ticketStatement = TicketStatementQuery.newBuilder() - .setStatementHandle(ByteString.copyFromUtf8( - DebugUtil.printId(flightStatementExecutor.getFinstId()) + ":" + query)).build(); - final Ticket ticket = new Ticket(Any.pack(ticketStatement).toByteArray()); - // TODO Support multiple endpoints. - Location location = Location.forGrpcInsecure(flightStatementExecutor.getResultFlightServerAddr().hostname, - flightStatementExecutor.getResultFlightServerAddr().port); - List endpoints = Collections.singletonList(new FlightEndpoint(ticket, location)); - - Schema schema; - schema = flightStatementExecutor.fetchArrowFlightSchema(5000); - if (schema == null) { - throw CallStatus.INTERNAL.withDescription("fetch arrow flight schema is null").toRuntimeException(); + final FlightSqlConnectProcessor flightSQLConnectProcessor = new FlightSqlConnectProcessor(connectContext); + + flightSQLConnectProcessor.handleQuery(query); + if (connectContext.getState().getStateType() == MysqlStateType.ERR) { + throw new RuntimeException("after handleQuery"); + } + + if (connectContext.isReturnResultFromLocal()) { + // set/use etc. stmt returns an OK result by default. + if (connectContext.getFlightSqlChannel().resultNum() == 0) { + // a random query id and add empty results + String queryId = UUID.randomUUID().toString(); + connectContext.getFlightSqlChannel().addEmptyResult(queryId, query); + + final ByteString handle = ByteString.copyFromUtf8(context.peerIdentity() + ":" + queryId); + TicketStatementQuery ticketStatement = TicketStatementQuery.newBuilder().setStatementHandle(handle) + .build(); + return getFlightInfoForSchema(ticketStatement, descriptor, + connectContext.getFlightSqlChannel().getResult(queryId).getVectorSchemaRoot().getSchema()); + } + + // A Flight Sql request can only contain one statement that returns result, + // otherwise expected thrown exception during execution. + Preconditions.checkState(connectContext.getFlightSqlChannel().resultNum() == 1); + + // The tokens used for authentication between getStreamStatement and getFlightInfoStatement + // are different. So put the peerIdentity into the ticket and then getStreamStatement is used to find + // the correct ConnectContext. + // queryId is used to find query results. + final ByteString handle = ByteString.copyFromUtf8( + context.peerIdentity() + ":" + DebugUtil.printId(connectContext.queryId())); + TicketStatementQuery ticketStatement = TicketStatementQuery.newBuilder().setStatementHandle(handle) + .build(); + return getFlightInfoForSchema(ticketStatement, descriptor, + connectContext.getFlightSqlChannel().getResult(DebugUtil.printId(connectContext.queryId())) + .getVectorSchemaRoot().getSchema()); + } else { + // Now only query stmt will pull results from BE. + final ByteString handle = ByteString.copyFromUtf8( + DebugUtil.printId(connectContext.getFinstId()) + ":" + query); + Schema schema = flightSQLConnectProcessor.fetchArrowFlightSchema(5000); + if (schema == null) { + throw CallStatus.INTERNAL.withDescription("fetch arrow flight schema is null").toRuntimeException(); + } + TicketStatementQuery ticketStatement = TicketStatementQuery.newBuilder().setStatementHandle(handle) + .build(); + Ticket ticket = new Ticket(Any.pack(ticketStatement).toByteArray()); + // TODO Support multiple endpoints. + Location location = Location.forGrpcInsecure(connectContext.getResultFlightServerAddr().hostname, + connectContext.getResultFlightServerAddr().port); + List endpoints = Collections.singletonList(new FlightEndpoint(ticket, location)); + // TODO Set in BE callback after query end, Client will not callback. + connectContext.setCommand(MysqlCommand.COM_SLEEP); + return new FlightInfo(schema, descriptor, endpoints, -1, -1); } - // TODO Set in BE callback after query end, Client client will not callback by default. - connectContext.setCommand(MysqlCommand.COM_SLEEP); - return new FlightInfo(schema, descriptor, endpoints, -1, -1); } catch (Exception e) { if (null != connectContext) { connectContext.setCommand(MysqlCommand.COM_SLEEP); + String errMsg = "get flight info statement failed, " + e.getMessage() + ", " + Util.getRootCauseMessage( + e) + ", error code: " + connectContext.getState().getErrorCode() + ", error msg: " + + connectContext.getState().getErrorMessage(); + LOG.warn(errMsg, e); + throw CallStatus.INTERNAL.withDescription(errMsg).withCause(e).toRuntimeException(); } LOG.warn("get flight info statement failed, " + e.getMessage(), e); throw CallStatus.INTERNAL.withDescription(Util.getRootCauseMessage(e)).withCause(e).toRuntimeException(); @@ -146,8 +191,7 @@ public FlightInfo getFlightInfoStatement(final CommandStatementQuery request, fi @Override public FlightInfo getFlightInfoPreparedStatement(final CommandPreparedStatementQuery command, - final CallContext context, - final FlightDescriptor descriptor) { + final CallContext context, final FlightDescriptor descriptor) { throw CallStatus.UNIMPLEMENTED.withDescription("getFlightInfoPreparedStatement unimplemented") .toRuntimeException(); } @@ -158,6 +202,42 @@ public SchemaResult getSchemaStatement(final CommandStatementQuery command, fina throw CallStatus.UNIMPLEMENTED.withDescription("getSchemaStatement unimplemented").toRuntimeException(); } + @Override + public void getStreamStatement(final TicketStatementQuery ticketStatementQuery, final CallContext context, + final ServerStreamListener listener) { + ConnectContext connectContext = null; + final String handle = ticketStatementQuery.getStatementHandle().toStringUtf8(); + String[] handleParts = handle.split(":"); + String executedPeerIdentity = handleParts[0]; + String queryId = handleParts[1]; + try { + // The tokens used for authentication between getStreamStatement and getFlightInfoStatement are different. + connectContext = flightSessionsManager.getConnectContext(executedPeerIdentity); + final FlightSqlResultCacheEntry flightSqlResultCacheEntry = Objects.requireNonNull( + connectContext.getFlightSqlChannel().getResult(queryId)); + final VectorSchemaRoot vectorSchemaRoot = flightSqlResultCacheEntry.getVectorSchemaRoot(); + listener.start(vectorSchemaRoot); + listener.putNext(); + } catch (Exception e) { + listener.error(e); + if (null != connectContext) { + String errMsg = "get stream statement failed, " + e.getMessage() + ", " + Util.getRootCauseMessage(e) + + ", error code: " + connectContext.getState().getErrorCode() + ", error msg: " + + connectContext.getState().getErrorMessage(); + LOG.warn(errMsg, e); + throw CallStatus.INTERNAL.withDescription(errMsg).withCause(e).toRuntimeException(); + } + LOG.warn("get stream statement failed, " + e.getMessage(), e); + throw CallStatus.INTERNAL.withDescription(Util.getRootCauseMessage(e)).withCause(e).toRuntimeException(); + } finally { + listener.completed(); + if (null != connectContext) { + // The result has been sent, delete it. + connectContext.getFlightSqlChannel().invalidate(queryId); + } + } + } + @Override public void close() throws Exception { AutoCloseables.close(rootAllocator); @@ -180,8 +260,7 @@ public void doExchange(CallContext context, FlightStream reader, ServerStreamLis } @Override - public Runnable acceptPutStatement(CommandStatementUpdate command, - CallContext context, FlightStream flightStream, + public Runnable acceptPutStatement(CommandStatementUpdate command, CallContext context, FlightStream flightStream, StreamListener ackStream) { throw CallStatus.UNIMPLEMENTED.withDescription("acceptPutStatement unimplemented").toRuntimeException(); } @@ -219,8 +298,7 @@ public FlightInfo getFlightInfoTypeInfo(CommandGetXdbcTypeInfo request, CallCont } @Override - public void getStreamTypeInfo(CommandGetXdbcTypeInfo request, CallContext context, - ServerStreamListener listener) { + public void getStreamTypeInfo(CommandGetXdbcTypeInfo request, CallContext context, ServerStreamListener listener) { throw CallStatus.UNIMPLEMENTED.withDescription("getStreamTypeInfo unimplemented").toRuntimeException(); } @@ -323,12 +401,6 @@ public void getStreamCrossReference(CommandGetCrossReference command, CallContex throw CallStatus.UNIMPLEMENTED.withDescription("getStreamCrossReference unimplemented").toRuntimeException(); } - @Override - public void getStreamStatement(final TicketStatementQuery ticketStatementQuery, final CallContext context, - final ServerStreamListener listener) { - throw CallStatus.UNIMPLEMENTED.withDescription("getStreamStatement unimplemented").toRuntimeException(); - } - private FlightInfo getFlightInfoForSchema(final T request, final FlightDescriptor descriptor, final Schema schema) { final Ticket ticket = new Ticket(Any.pack(request).toByteArray()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/FlightStatementExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/FlightSqlConnectProcessor.java similarity index 65% rename from fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/FlightStatementExecutor.java rename to fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/FlightSqlConnectProcessor.java index 8c9cdf124f3485..ef5b53c2d1ff75 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/FlightStatementExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/FlightSqlConnectProcessor.java @@ -14,18 +14,19 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. -// This file is copied from -// https://github.com/apache/arrow/blob/main/java/flight/flight-sql/src/test/java/org/apache/arrow/flight/sql/example/StatementContext.java -// and modified by Doris package org.apache.doris.service.arrowflight; import org.apache.doris.analysis.Expr; +import org.apache.doris.common.ErrorCode; +import org.apache.doris.common.ErrorReport; import org.apache.doris.common.Status; import org.apache.doris.common.util.DebugUtil; +import org.apache.doris.mysql.MysqlCommand; import org.apache.doris.proto.InternalService; import org.apache.doris.proto.Types; import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.ConnectProcessor; import org.apache.doris.qe.StmtExecutor; import org.apache.doris.rpc.BackendServiceProxy; import org.apache.doris.rpc.RpcException; @@ -33,112 +34,84 @@ import org.apache.doris.thrift.TStatusCode; import org.apache.doris.thrift.TUniqueId; +import io.opentelemetry.api.trace.Span; +import io.opentelemetry.context.Scope; import org.apache.arrow.memory.RootAllocator; import org.apache.arrow.vector.FieldVector; import org.apache.arrow.vector.VectorSchemaRoot; import org.apache.arrow.vector.ipc.ArrowStreamReader; import org.apache.arrow.vector.types.pojo.Schema; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.ByteArrayInputStream; import java.util.ArrayList; import java.util.List; -import java.util.Objects; -import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -public final class FlightStatementExecutor implements AutoCloseable { - private ConnectContext connectContext; - private final String query; - private TUniqueId queryId; - private TUniqueId finstId; - private TNetworkAddress resultFlightServerAddr; - private TNetworkAddress resultInternalServiceAddr; - private ArrayList resultOutputExprs; - - public FlightStatementExecutor(final String query, ConnectContext connectContext) { - this.query = query; - this.connectContext = connectContext; - connectContext.setThreadLocalInfo(); - } - - public void setQueryId(TUniqueId queryId) { - this.queryId = queryId; - } - - public void setFinstId(TUniqueId finstId) { - this.finstId = finstId; - } - - public void setResultFlightServerAddr(TNetworkAddress resultFlightServerAddr) { - this.resultFlightServerAddr = resultFlightServerAddr; - } - - public void setResultInternalServiceAddr(TNetworkAddress resultInternalServiceAddr) { - this.resultInternalServiceAddr = resultInternalServiceAddr; - } - - public void setResultOutputExprs(ArrayList resultOutputExprs) { - this.resultOutputExprs = resultOutputExprs; - } - - public String getQuery() { - return query; - } - - public TUniqueId getQueryId() { - return queryId; - } - - public TUniqueId getFinstId() { - return finstId; - } - - public TNetworkAddress getResultFlightServerAddr() { - return resultFlightServerAddr; - } - - public TNetworkAddress getResultInternalServiceAddr() { - return resultInternalServiceAddr; - } - - public ArrayList getResultOutputExprs() { - return resultOutputExprs; - } - - @Override - public boolean equals(final Object other) { - if (!(other instanceof FlightStatementExecutor)) { - return false; +/** + * Process one flgiht sql connection. + */ +public class FlightSqlConnectProcessor extends ConnectProcessor implements AutoCloseable { + private static final Logger LOG = LogManager.getLogger(FlightSqlConnectProcessor.class); + + public FlightSqlConnectProcessor(ConnectContext context) { + super(context); + connectType = ConnectType.ARROW_FLIGHT_SQL; + context.setThreadLocalInfo(); + context.setReturnResultFromLocal(true); + } + + public void prepare(MysqlCommand command) { + // set status of query to OK. + ctx.getState().reset(); + executor = null; + + if (command == null) { + ErrorReport.report(ErrorCode.ERR_UNKNOWN_COM_ERROR); + ctx.getState().setError(ErrorCode.ERR_UNKNOWN_COM_ERROR, "Unknown command(" + command.toString() + ")"); + LOG.warn("Unknown command(" + command + ")"); + return; } - return this == other; + LOG.debug("arrow flight sql handle command {}", command); + ctx.setCommand(command); + ctx.setStartTime(); } - @Override - public int hashCode() { - return Objects.hash(this); - } + public void handleQuery(String query) { + MysqlCommand command = MysqlCommand.COM_QUERY; + prepare(command); - public void executeQuery() { - try { - UUID uuid = UUID.randomUUID(); - TUniqueId queryId = new TUniqueId(uuid.getMostSignificantBits(), uuid.getLeastSignificantBits()); - setQueryId(queryId); - connectContext.setQueryId(queryId); - StmtExecutor stmtExecutor = new StmtExecutor(connectContext, getQuery()); - connectContext.setExecutor(stmtExecutor); - stmtExecutor.executeArrowFlightQuery(this); + ctx.setRunningQuery(query); + ctx.initTracer("trace"); + Span rootSpan = ctx.getTracer().spanBuilder("handleQuery").setNoParent().startSpan(); + try (Scope scope = rootSpan.makeCurrent()) { + handleQuery(command, query); } catch (Exception e) { - throw new RuntimeException("Failed to coord exec", e); + rootSpan.recordException(e); + throw e; + } finally { + rootSpan.end(); } } + // TODO + // private void handleInitDb() { + // handleInitDb(fullDbName); + // } + + // TODO + // private void handleFieldList() { + // handleFieldList(tableName); + // } + public Schema fetchArrowFlightSchema(int timeoutMs) { - TNetworkAddress address = getResultInternalServiceAddr(); - TUniqueId tid = getFinstId(); - ArrayList resultOutputExprs = getResultOutputExprs(); + TNetworkAddress address = ctx.getResultInternalServiceAddr(); + TUniqueId tid = ctx.getFinstId(); + ArrayList resultOutputExprs = ctx.getResultOutputExprs(); Types.PUniqueId finstId = Types.PUniqueId.newBuilder().setHi(tid.hi).setLo(tid.lo).build(); try { InternalService.PFetchArrowFlightSchemaRequest request = @@ -156,7 +129,7 @@ public Schema fetchArrowFlightSchema(int timeoutMs) { } TStatusCode code = TStatusCode.findByValue(pResult.getStatus().getStatusCode()); if (code != TStatusCode.OK) { - Status status = null; + Status status = new Status(); status.setPstatus(pResult.getStatus()); throw new RuntimeException(String.format("fetch arrow flight schema failed, finstId: %s, errmsg: %s", DebugUtil.printId(tid), status)); @@ -204,6 +177,14 @@ public Schema fetchArrowFlightSchema(int timeoutMs) { @Override public void close() throws Exception { + ctx.setCommand(MysqlCommand.COM_SLEEP); + // TODO support query profile + for (StmtExecutor asynExecutor : returnResultFromRemoteExecutor) { + asynExecutor.finalizeQuery(); + } + returnResultFromRemoteExecutor.clear(); ConnectContext.remove(); } } + + diff --git a/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/results/FlightSqlChannel.java b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/results/FlightSqlChannel.java new file mode 100644 index 00000000000000..174e733c2db1a0 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/results/FlightSqlChannel.java @@ -0,0 +1,147 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.service.arrowflight.results; + +import org.apache.doris.catalog.Column; +import org.apache.doris.common.FeConstants; +import org.apache.doris.qe.ResultSet; +import org.apache.doris.qe.ResultSetMetaData; + +import com.google.common.cache.Cache; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.RemovalListener; +import com.google.common.cache.RemovalNotification; +import org.apache.arrow.memory.BufferAllocator; +import org.apache.arrow.memory.RootAllocator; +import org.apache.arrow.util.AutoCloseables; +import org.apache.arrow.vector.FieldVector; +import org.apache.arrow.vector.VarCharVector; +import org.apache.arrow.vector.VectorSchemaRoot; +import org.apache.arrow.vector.types.pojo.ArrowType.Utf8; +import org.apache.arrow.vector.types.pojo.Field; +import org.apache.arrow.vector.types.pojo.FieldType; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class FlightSqlChannel { + private final Cache resultCache; + private final BufferAllocator allocator; + + public FlightSqlChannel() { + // The Stmt result is not picked up by the Client within 10 minutes and will be deleted. + resultCache = + CacheBuilder.newBuilder() + .maximumSize(100) + .expireAfterWrite(10, TimeUnit.MINUTES) + .removalListener(new ResultRemovalListener()) + .build(); + allocator = new RootAllocator(Long.MAX_VALUE); + } + + // TODO + public String getRemoteIp() { + return "0.0.0.0"; + } + + // TODO + public String getRemoteHostPortString() { + return "0.0.0.0:0"; + } + + public void addResult(String queryId, String runningQuery, ResultSet resultSet) { + List schemaFields = new ArrayList<>(); + List dataFields = new ArrayList<>(); + List> resultData = resultSet.getResultRows(); + ResultSetMetaData metaData = resultSet.getMetaData(); + + // TODO: only support varchar type + for (Column col : metaData.getColumns()) { + schemaFields.add(new Field(col.getName(), FieldType.nullable(new Utf8()), null)); + VarCharVector varCharVector = new VarCharVector(col.getName(), allocator); + varCharVector.allocateNew(); + varCharVector.setValueCount(resultData.size()); + dataFields.add(varCharVector); + } + + for (int i = 0; i < resultData.size(); i++) { + List row = resultData.get(i); + for (int j = 0; j < row.size(); j++) { + String item = row.get(j); + if (item == null || item.equals(FeConstants.null_string)) { + dataFields.get(j).setNull(i); + } else { + ((VarCharVector) dataFields.get(j)).setSafe(i, item.getBytes()); + } + } + } + VectorSchemaRoot vectorSchemaRoot = new VectorSchemaRoot(schemaFields, dataFields); + final FlightSqlResultCacheEntry flightSqlResultCacheEntry = new FlightSqlResultCacheEntry(vectorSchemaRoot, + runningQuery); + resultCache.put(queryId, flightSqlResultCacheEntry); + } + + public void addEmptyResult(String queryId, String query) { + List schemaFields = new ArrayList<>(); + List dataFields = new ArrayList<>(); + schemaFields.add(new Field("StatusResult", FieldType.nullable(new Utf8()), null)); + VarCharVector varCharVector = new VarCharVector("StatusResult", allocator); + varCharVector.allocateNew(); + varCharVector.setValueCount(1); + varCharVector.setSafe(0, "OK".getBytes()); + dataFields.add(varCharVector); + + VectorSchemaRoot vectorSchemaRoot = new VectorSchemaRoot(schemaFields, dataFields); + final FlightSqlResultCacheEntry flightSqlResultCacheEntry = new FlightSqlResultCacheEntry(vectorSchemaRoot, + query); + resultCache.put(queryId, flightSqlResultCacheEntry); + } + + public FlightSqlResultCacheEntry getResult(String queryId) { + return resultCache.getIfPresent(queryId); + } + + public void invalidate(String handle) { + resultCache.invalidate(handle); + } + + public long resultNum() { + return resultCache.size(); + } + + public void reset() { + resultCache.invalidateAll(); + } + + public void close() { + reset(); + } + + private static class ResultRemovalListener implements RemovalListener { + @Override + public void onRemoval(@NotNull final RemovalNotification notification) { + try { + AutoCloseables.close(notification.getValue()); + } catch (final Exception e) { + // swallow + } + } + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/results/FlightSqlResultCacheEntry.java b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/results/FlightSqlResultCacheEntry.java new file mode 100644 index 00000000000000..12ce04ca8ed842 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/results/FlightSqlResultCacheEntry.java @@ -0,0 +1,64 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.service.arrowflight.results; + +import org.apache.arrow.vector.VectorSchemaRoot; + +import java.util.Objects; + + +public final class FlightSqlResultCacheEntry implements AutoCloseable { + + private final VectorSchemaRoot vectorSchemaRoot; + private final String query; + + public FlightSqlResultCacheEntry(final VectorSchemaRoot vectorSchemaRoot, final String query) { + this.vectorSchemaRoot = Objects.requireNonNull(vectorSchemaRoot, "result cannot be null."); + this.query = query; + } + + public VectorSchemaRoot getVectorSchemaRoot() { + return vectorSchemaRoot; + } + + public String getQuery() { + return query; + } + + @Override + public void close() throws Exception { + vectorSchemaRoot.clear(); + } + + @Override + public boolean equals(final Object other) { + if (this == other) { + return true; + } + if (!(other instanceof VectorSchemaRoot)) { + return false; + } + final VectorSchemaRoot that = (VectorSchemaRoot) other; + return vectorSchemaRoot.equals(that); + } + + @Override + public int hashCode() { + return Objects.hash(vectorSchemaRoot); + } +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSessionsManager.java b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSessionsManager.java index ed01098c675652..f850384d4ed96c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSessionsManager.java +++ b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSessionsManager.java @@ -49,8 +49,8 @@ public interface FlightSessionsManager { */ ConnectContext createConnectContext(String peerIdentity); - public static ConnectContext buildConnectContext(String peerIdentity, UserIdentity userIdentity, String remoteIP) { - ConnectContext connectContext = new ConnectContext(peerIdentity); + static ConnectContext buildConnectContext(String peerIdentity, UserIdentity userIdentity, String remoteIP) { + ConnectContext connectContext = new FlightSqlConnectContext(peerIdentity); connectContext.setEnv(Env.getCurrentEnv()); connectContext.setStartTime(); connectContext.setCluster(SystemInfoService.DEFAULT_CLUSTER); diff --git a/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSessionsWithTokenManager.java b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSessionsWithTokenManager.java index ce12f610ea27a0..e1866b094b2641 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSessionsWithTokenManager.java +++ b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSessionsWithTokenManager.java @@ -58,6 +58,7 @@ public ConnectContext createConnectContext(String peerIdentity) { if (flightTokenDetails.getCreatedSession()) { return null; } + flightTokenDetails.setCreatedSession(true); return FlightSessionsManager.buildConnectContext(peerIdentity, flightTokenDetails.getUserIdentity(), flightTokenDetails.getRemoteIp()); } catch (IllegalArgumentException e) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSqlConnectContext.java b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSqlConnectContext.java new file mode 100644 index 00000000000000..9f703dff92b1a9 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/service/arrowflight/sessions/FlightSqlConnectContext.java @@ -0,0 +1,104 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.service.arrowflight.sessions; + +import org.apache.doris.mysql.MysqlChannel; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.ConnectProcessor; +import org.apache.doris.service.arrowflight.results.FlightSqlChannel; +import org.apache.doris.thrift.TResultSinkType; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; + +public class FlightSqlConnectContext extends ConnectContext { + private static final Logger LOG = LogManager.getLogger(FlightSqlConnectContext.class); + protected volatile FlightSqlChannel flightSqlChannel; + + public FlightSqlConnectContext(String peerIdentity) { + this.connectType = ConnectType.ARROW_FLIGHT_SQL; + this.peerIdentity = peerIdentity; + mysqlChannel = null; // Use of MysqlChannel is not expected + flightSqlChannel = new FlightSqlChannel(); + setResultSinkType(TResultSinkType.ARROW_FLIGHT_PROTOCAL); + init(); + } + + @Override + public FlightSqlChannel getFlightSqlChannel() { + return flightSqlChannel; + } + + @Override + public MysqlChannel getMysqlChannel() { + throw new RuntimeException("getMysqlChannel not in mysql connection"); + } + + @Override + public String getClientIP() { + return flightSqlChannel.getRemoteHostPortString(); + } + + @Override + protected void closeChannel() { + if (flightSqlChannel != null) { + flightSqlChannel.close(); + } + } + + // kill operation with no protect. + @Override + public void kill(boolean killConnection) { + LOG.warn("kill query from {}, kill flight sql connection: {}", getRemoteHostPortString(), killConnection); + + if (killConnection) { + isKilled = true; + closeChannel(); + connectScheduler.unregisterConnection(this); + } + // Now, cancel running query. + cancelQuery(); + } + + @Override + public String getRemoteHostPortString() { + return getFlightSqlChannel().getRemoteHostPortString(); + } + + @Override + public void startAcceptQuery(ConnectProcessor connectProcessor) { + throw new RuntimeException("Flight Sql Not impl startAcceptQuery"); + } + + @Override + public void suspendAcceptQuery() { + throw new RuntimeException("Flight Sql Not impl suspendAcceptQuery"); + } + + @Override + public void resumeAcceptQuery() { + throw new RuntimeException("Flight Sql Not impl resumeAcceptQuery"); + } + + @Override + public void stopAcceptQuery() throws IOException { + throw new RuntimeException("Flight Sql Not impl stopAcceptQuery"); + } +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java b/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java index 507102fb0d258d..dcc0d85cb479a5 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/qe/StmtExecutorTest.java @@ -38,6 +38,7 @@ import org.apache.doris.mysql.MysqlChannel; import org.apache.doris.mysql.MysqlSerializer; import org.apache.doris.planner.OriginalPlanner; +import org.apache.doris.qe.ConnectContext.ConnectType; import org.apache.doris.rewrite.ExprRewriter; import org.apache.doris.service.FrontendOptions; import org.apache.doris.thrift.TQueryOptions; @@ -380,6 +381,10 @@ public void testKillOtherFail(@Mocked KillStmt killStmt, @Mocked SqlParser parse killCtx.kill(true); minTimes = 0; + killCtx.getConnectType(); + minTimes = 0; + result = ConnectType.MYSQL; + ConnectContext.get(); minTimes = 0; result = ctx; @@ -437,6 +442,10 @@ public void testKillOther(@Mocked KillStmt killStmt, @Mocked SqlParser parser, killCtx.kill(true); minTimes = 0; + killCtx.getConnectType(); + minTimes = 0; + result = ConnectType.MYSQL; + ConnectContext.get(); minTimes = 0; result = ctx; From 290070074a194f795ddd7389b823e97701f07a0c Mon Sep 17 00:00:00 2001 From: AKIRA <33112463+Kikyou1997@users.noreply.github.com> Date: Wed, 8 Nov 2023 12:03:44 +0900 Subject: [PATCH 30/88] [refactor](stats) refactor collection logic and opt some config (#26163) 1. not collect partition stats anymore 2. merge insert of stats 3. delete period collector since it is useless 4. remove enable_auto_sample 5. move some config related to stats to global session variable Before this PR, when analyze a table, the insert count equals column count times 2 After this PR, insert count of analyze table would reduce to column count / insert_merge_item_count. According to my test, when analyzing tpch lineitem, the insert sql count is 1 --- docs/en/docs/query-acceleration/statistics.md | 328 ++++++++++-------- .../docs/query-acceleration/statistics.md | 275 ++++++++------- .../java/org/apache/doris/common/Config.java | 34 +- .../java/org/apache/doris/catalog/Env.java | 7 - .../org/apache/doris/catalog/OlapTable.java | 7 +- .../doris/nereids/stats/StatsCalculator.java | 4 + .../org/apache/doris/qe/SessionVariable.java | 58 +++- .../apache/doris/statistics/AnalysisJob.java | 193 +++++++++++ .../doris/statistics/AnalysisManager.java | 90 ++--- .../statistics/AnalysisTaskExecutor.java | 28 +- .../doris/statistics/AnalysisTaskWrapper.java | 16 +- .../doris/statistics/BaseAnalysisTask.java | 110 ++---- .../apache/doris/statistics/ColStatsData.java | 14 + .../doris/statistics/HMSAnalysisTask.java | 135 +------ .../doris/statistics/JdbcAnalysisTask.java | 34 +- .../doris/statistics/MVAnalysisTask.java | 152 -------- .../doris/statistics/OlapAnalysisTask.java | 138 +------- .../doris/statistics/StatisticConstants.java | 14 +- .../statistics/StatisticsAutoCollector.java | 9 +- .../doris/statistics/StatisticsCollector.java | 11 +- .../statistics/StatisticsPeriodCollector.java | 50 --- .../org/apache/doris/statistics/StatsId.java | 15 +- .../doris/statistics/util/StatisticsUtil.java | 81 ++++- .../doris/statistics/AnalysisJobTest.java | 233 ++++++++----- .../doris/statistics/AnalysisManagerTest.java | 37 +- .../statistics/AnalysisTaskExecutorTest.java | 16 +- .../apache/doris/statistics/AnalyzeTest.java | 185 ++++++++++ .../apache/doris/statistics/CacheTest.java | 40 ++- .../statistics/OlapAnalysisTaskTest.java | 74 ++-- .../StatisticsAutoCollectorTest.java | 73 ++++ .../statistics/util/StatisticsUtilTest.java | 46 ++- .../suites/statistics/analyze_stats.groovy | 100 +++++- .../statistics/test_agg_complex_type.groovy | 53 +++ 33 files changed, 1544 insertions(+), 1116 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisJob.java delete mode 100644 fe/fe-core/src/main/java/org/apache/doris/statistics/MVAnalysisTask.java delete mode 100644 fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsPeriodCollector.java create mode 100644 fe/fe-core/src/test/java/org/apache/doris/statistics/AnalyzeTest.java create mode 100644 regression-test/suites/statistics/test_agg_complex_type.groovy diff --git a/docs/en/docs/query-acceleration/statistics.md b/docs/en/docs/query-acceleration/statistics.md index 069c25fb1a899a..c25054094b6e84 100644 --- a/docs/en/docs/query-acceleration/statistics.md +++ b/docs/en/docs/query-acceleration/statistics.md @@ -26,33 +26,33 @@ under the License. # Statistics -## Introduction to statistics information +Collecting statistics helps the optimizer understand data distribution characteristics. When performing Cost-Based Optimization (CBO), the optimizer uses these statistics to calculate the selectivity of predicates and estimate the cost of each execution plan. This allows for the selection of more optimal plans, significantly improving query efficiency. -Collecting statistics helps the optimizer understand data distribution characteristics. When performing Cost-Based Optimization (CBO), the optimizer utilizes these statistics to calculate the selectivity of predicates and estimate the cost of each execution plan. This enables the selection of more efficient plans, significantly improving query performance. +Currently, the following information is collected for each column: -Currently, the collected column-level information includes: +| Information | Description | +| :----------------- | :------------------------------ | +| `row_count` | Total number of rows | +| `data_size` | Total data size | +| `avg_size_byte` | Average length of values | +| `ndv` | Number of distinct values | +| `min` | Minimum value | +| `max` | Maximum value | +| `null_count` | Number of null values | -| Information | Description | -| :--------------- | :------------------------ | -| `row_count` | Total number of rows | -| `data_size` | Total data size | -| `avg_size_byte` | Average length of values | -| `ndv` | Number of distinct values | -| `min` | Minimum value | -| `max` | Maximum value | -| `null_count` | Number of null values | -## Collecting Statistics +## 1. Collecting Statistics -### Using the ANALYZE Statement +--- + +### 1.1 Manual Collection Using ANALYZE Statement -Doris supports users in triggering the collection and updating of statistics by submitting the ANALYZE statement. +Doris allows users to manually trigger the collection and update of statistics by submitting the ANALYZE statement. Syntax: ```SQL -ANALYZE < TABLE | DATABASE table_name | db_name > - [ PARTITIONS [(*) | (partition_name [, ...]) | WITH RECENT COUNT ] ] +ANALYZE < TABLE | DATABASE table_name | db_name > [ (column_name [, ...]) ] [ [ WITH SYNC ] [ WITH SAMPLE PERCENT | ROWS ] [ WITH SQL ] ] [ PROPERTIES ("key" = "value", ...) ]; @@ -60,60 +60,110 @@ ANALYZE < TABLE | DATABASE table_name | db_name > Where: -- `table_name`: Specifies the target table. It can be in the `db_name.table_name` format. -- `partition_name`: The specified target partitions(for hive external table only)。Must be partitions exist in `table_name`. Multiple partition names are separated by commas. e.g. for single level partition: PARTITIONS(`event_date=20230706`), for multi level partition: PARTITIONS(`nation=US/city=Washington`). PARTITIONS(*) specifies all partitions, PARTITIONS WITH RECENT 30 specifies the latest 30 partitions. -- `column_name`: Specifies the target column. It must be an existing column in `table_name`, and multiple column names are separated by commas. -- `sync`: Collect statistics synchronously. Returns upon completion. If not specified, it executes asynchronously and returns a task ID. -- `sample percent | rows`: Collect statistics using sampling. You can specify either the sampling percentage or the number of sampled rows. -- `sql`: Collect statistics for external partition column with sql. By default, it uses meta data for partition columns, which is faster but may inaccurate for row count and size. Using sql could collect the accurate stats. +- `table_name`: The specified target table. It can be in the format `db_name.table_name`. +- `column_name`: The specified target column. It must be an existing column in `table_name`. You can specify multiple column names separated by commas. +- `sync`: Collect statistics synchronously. Returns after collection. If not specified, it executes asynchronously and returns a JOB ID. +- `sample percent | rows`: Collect statistics with sampling. You can specify a sampling percentage or a number of sampling rows. +- `sql`: Execute SQL to collect statistics for partitioned columns in external tables. By default, partitioned column information is collected from metadata, which is efficient but may not be accurate in terms of row count and data size. Users can specify using SQL to collect accurate partitioned column information. + +Here are some examples: + +Collect statistics for a table with a 10% sampling rate: + +```sql +ANALYZE TABLE lineitem WITH SAMPLE PERCENT 10; +``` + +Collect statistics for a table with a sample of 100,000 rows: -### Automatic Statistics Collection +```sql +ANALYZE TABLE lineitem WITH SAMPLE ROWS 100000; +``` + +
+ +### 1.2 Automatic Collection -Users can enable this feature by setting the FE configuration option `enable_full_auto_analyze = true`. Once enabled, statistics on qualifying tables and columns will be automatically collected during specified time intervals. Users can specify the automatic collection time period by setting the `full_auto_analyze_start_time` (default is 00:00:00) and `full_auto_analyze_end_time` (default is 02:00:00) parameters. +This feature has been officially supported since 2.0.3 and is enabled by default. The basic operation logic is described below. After each import transaction commit, Doris records the number of rows updated by the import transaction to estimate the health of the existing table's statistics data (for tables that have not collected statistics, their health is 0). When the health of a table is below 60 (adjustable through the `table_stats_health_threshold` parameter), Doris considers the statistics for that table outdated and triggers statistics collection jobs for that table in subsequent operations. For tables with a health value above 60, no repeated collection is performed. -This feature collects statistics only for tables and columns that either have no statistics or have outdated statistics. When more than 20% of the data in a table is updated (this value can be configured using the `table_stats_health_threshold` parameter with a default of 80), Doris considers the statistics for that table to be outdated. +The collection jobs for statistics themselves consume a certain amount of system resources. To minimize the overhead, for tables with a large amount of data (default 5 GiB, adjustable with the FE parameter `huge_table_lower_bound_size_in_bytes`), Doris automatically uses sampling to collect statistics. Automatic sampling defaults to sampling 4,194,304 (2^22) rows to reduce the system's burden and complete the collection job as quickly as possible. If you want to sample more rows to obtain a more accurate data distribution, you can increase the sampling row count by adjusting the `huge_table_default_sample_rows` parameter. In addition, for tables with data larger than `huge_table_lower_bound_size_in_bytes` * 5, Doris ensures that the collection time interval is not less than 12 hours (which can be controlled by adjusting the `huge_table_auto_analyze_interval_in_millis` parameter). -For tables with a large amount of data (default is 5GiB), Doris will automatically use sampling to collect statistics, reducing the impact on the system and completing the collection job as quickly as possible. Users can adjust this behavior by setting the `huge_table_lower_bound_size_in_bytes` FE parameter. If you want to collect statistics for all tables in full, you can set the `enable_auto_sample` FE parameter to false. For tables with data size greater than `huge_table_lower_bound_size_in_bytes`, Doris ensures that the collection interval is not less than 12 hours (this time can be controlled using the `huge_table_auto_analyze_interval_in_millis` FE parameter). +If you are concerned about automatic collection jobs interfering with your business, you can specify a time frame for the automatic collection jobs to run during low business loads by setting the `full_auto_analyze_start_time` and `full_auto_analyze_end_time` parameters according to your needs. You can also completely disable this feature by setting the `enable_full_auto_analyze` parameter to `false`. -The default sample size for automatic sampling is 4194304(2^22) rows, but the actual sample size may be larger due to implementation reasons. If you want to sample more rows to obtain more accurate data distribution information, you can configure the `huge_table_default_sample_rows` FE parameter. +
-### Task Management -#### Viewing Analyze Tasks -You can use `SHOW ANALYZE` to view information about statistics collection tasks. +## 2. Job Management + +--- + +### 2.1 View Analyze Jobs + +Use `SHOW ANALYZE` to view information about statistics collection jobs. Syntax: ```SQL -SHOW ANALYZE < table_name | job_id > +SHOW [AUTO] ANALYZE < table_name | job_id > [ WHERE [ STATE = [ "PENDING" | "RUNNING" | "FINISHED" | "FAILED" ] ] ]; ``` -- `table_name`: Specifies the table for which you want to view statistics collection tasks. It can be in the form of `db_name.table_name`. If not specified, it returns information for all statistics collection tasks. -- `job_id`: The job ID of the statistics information task returned when executing `ANALYZE`. If not specified, it returns information for all statistics collection tasks. +- AUTO: Show historical information for automatic collection jobs only. Note that, by default, the status of only the last 20,000 completed automatic collection jobs is retained. +- table_name: Table name, specify to view statistics job information for that table. It can be in the format `db_name.table_name`. When not specified, it returns information for all statistics jobs. +- job_id: Job ID for statistics collection, obtained when executing `ANALYZE`. When not specified, this command returns information for all statistics jobs. Output: -| Column Name | Description | -| :-------------------- | :------------- | -| `job_id` | Job ID | -| `catalog_name` | Catalog Name | -| `db_name` | Database Name | -| `tbl_name` | Table Name | -| `col_name` | Column Name | -| `job_type` | Job Type | -| `analysis_type` | Analysis Type | -| `message` | Task Message | -| `last_exec_time_in_ms`| Last Execution Time | -| `state` | Task State | -| `schedule_type` | Schedule Type | +| Column Name | Description | +| :--------------------- | :--------------- | +| `job_id` | Job ID | +| `catalog_name` | Catalog Name | +| `db_name` | Database Name | +| `tbl_name` | Table Name | +| `col_name` | Column Name List | +| `job_type` | Job Type | +| `analysis_type` | Analysis Type | +| `message` | Job Information | +| `last_exec_time_in_ms` | Last Execution Time | +| `state` | Job Status | +| `schedule_type` | Scheduling Method | + +Here's an example: +```sql +mysql> show analyze 245073\G; +*************************** 1. row *************************** + job_id: 245073 + catalog_name: internal + db_name: default_cluster:tpch + tbl_name: lineitem + col_name: [l_returnflag,l_receiptdate,l_tax,l_shipmode,l_suppkey,l_shipdate,l_commitdate,l_partkey,l_orderkey,l_quantity,l_linestatus,l_comment,l_extendedprice,l_linenumber,l_discount,l_shipinstruct] + job_type: MANUAL + analysis_type: FUNDAMENTALS + message: +last_exec_time_in_ms: 2023-11-07 11:00:52 + state: FINISHED + progress: 16 Finished | 0 Failed | 0 In Progress | 16 Total + schedule_type: ONCE +``` + +
+ +### 2.2 View Column Statistics Collection Status + +Each collection job can contain one or more tasks, with each task corresponding to the collection of a column. Users can use the following command to view the completion status of statistics collection for each column. + +Syntax: + +```sql +SHOW ANALYZE TASK STATUS [job_id] +``` -You can use `SHOW ANALYZE TASK STATUS [job_id]` to check the completion status of collecting statistics for each column. +Here's an example: ``` -mysql> show analyze task status 20038; +mysql> show analyze task status 20038 ; +---------+----------+---------+----------------------+----------+ | task_id | col_name | message | last_exec_time_in_ms | state | +---------+----------+---------+----------------------+----------+ @@ -124,31 +174,49 @@ mysql> show analyze task status 20038; +---------+----------+---------+----------------------+----------+ ``` -#### Terminating Analyze Tasks +
-You can terminate running statistics collection tasks using `KILL ANALYZE`. +### 2.3 View Column Statistics + +Use `SHOW COLUMN STATS` to view various statistics data for columns. Syntax: ```SQL -KILL ANALYZE job_id; +SHOW COLUMN [cached] STATS table_name [ (column_name [, ...]) ]; ``` -- `job_id`: The job ID of the statistics information task. It is returned when executing `ANALYZE`, or you can obtain it using the `SHOW ANALYZE` statement. +Where: -Example: +- cached: Show statistics information in the current FE memory cache. +- table_name: The target table for collecting statistics. It can be in the format `db_name.table_name`. +- column_name: Specifies the target column, which must be an existing column in `table_name`. You can specify multiple column names separated by commas. -- Terminating statistics collection task with job ID 52357. +Here's an example: -```SQL -mysql> KILL ANALYZE 52357; +```sql +mysql> show column stats lineitem(l_tax)\G; +*************************** 1. row *************************** + column_name: l_tax + count: 6001215.0 + ndv: 9.0 + num_null: 0.0 + data_size: 4.800972E7 +avg_size_byte: 8.0 + min: 0.00 + max: 0.08 + method: FULL + type: FUNDAMENTALS + trigger: MANUAL + query_times: 0 + updated_time: 2023-11-07 11:00:46 ``` -#### Viewing Statistics Information +
-#### Table Statistics Information +### 2.4 Table Collection Overview -You can use `SHOW TABLE STATS` to view an overview of statistics collection for a table. +Use `SHOW TABLE STATS` to view an overview of statistics collection for a table. Syntax: @@ -156,124 +224,102 @@ Syntax: SHOW TABLE STATS table_name; ``` -- `table_name`: The name of the table for which you want to view statistics collection information. It can be in the form of `db_name.table_name`. - -Output: - -| Column Name | Description | -| :--------------- | :------------------------------------- | -| `row_count` | Number of rows (may not be the exact count at the time of execution) | -| `method` | Collection method (FULL/SAMPLE) | -| `type` | Type of statistics data | -| `updated_time` | Last update time | -| `columns` | Columns for which statistics were collected | -| `trigger` | Trigger method for statistics collection (Auto/User) | - - -#### Viewing Column Statistics Information - -You can use `SHOW COLUMN [cached] STATS` to view information about the number of distinct values and NULLs in columns. - -Syntax: +Where: -```SQL -SHOW COLUMN [cached] STATS table_name [ (column_name [, ...]) ]; -``` +- table_name: The target table name. It can be in the format `db_name.table_name`. -- `cached`: Displays statistics information from the current FE memory cache. -- `table_name`: The name of the table for which you want to view column statistics information. It can be in the form of `db_name.table_name`. -- `column_name`: The specific column(s) you want to view statistics for. It must be a column that exists in `table_name`, and multiple column names can be separated by commas. +Output: -#### Modifying Statistics Information +| Column Name | Description | +| :--------------------- | :--------------- | +| `updated_rows` | Updated rows since the last ANALYZE | +| `query_times` | Reserved column for recording the number of times the table was queried in future versions | +| `row_count` | Number of rows (does not reflect the exact number of rows at the time of command execution) | +| `updated_time` | Last update time | +| `columns` | Columns for which statistics information has been collected | -Users can adjust statistics information using the `ALTER` statement. +Here's an example: -```SQL -ALTER TABLE table_name MODIFY COLUMN column_name SET STATS ('stat_name' = 'stat_value', ...) [ PARTITION (partition_name) ]; +```sql +mysql> show table stats lineitem \G; +*************************** 1. row *************************** +updated_rows: 0 + query_times: 0 + row_count: 6001215 +updated_time: 2023-11-07 + columns: [l_returnflag, l_receiptdate, l_tax, l_shipmode, l_suppkey, l_shipdate, l_commitdate, l_partkey, l_orderkey, l_quantity, l_linestatus, l_comment, l_extendedprice, l_linenumber, l_discount, l_shipinstruct] + trigger: MANUAL ``` -- `table_name`: The name of the table for which you want to modify statistics information. It can be in the form of `db_name.table_name`. -- `column_name`: The specific column for which you want to modify statistics information. It must be a column that exists in `table_name`, and you can modify statistics information for one column at a time. -- `stat_name` and `stat_value`: The corresponding statistics information name and its value. Multiple statistics can be modified, separated by commas. You can modify statistics such as `row_count`, `ndv`, `num_nulls`, `min_value`, `max_value`, and `data_size`. +
-#### Delete Statistics +### 2.5 Terminate Statistics Jobs -Users can delete statistics using the `DROP` statement, which allows them to specify the table, partition, or column for which they want to delete statistics based on the provided parameters. When deleted, both column statistics and column histogram information are removed. +Use `KILL ANALYZE` to terminate running statistics jobs. Syntax: ```SQL -DROP [ EXPIRED ] STATS [ table_name [ (column_name [, ...]) ] ]; +KILL ANALYZE job_id; ``` -#### Delete Analyze Job - -Used to delete automatic/periodic Analyze jobs based on the job ID. +Where: -```sql -DROP ANALYZE JOB [JOB_ID] -``` +- job_id: Job ID for statistics collection. Obtained when performing asynchronous statistics collection using the `ANALYZE` statement, and it can also be obtained through the `SHOW ANALYZE` statement. -### View Automatic Collection Task Execution Status +Example: -This command is used to check the completion status of automatic collection tasks after enabling automatic collection functionality. +- Terminate statistics job with ID 52357. -```sql -SHOW AUTO ANALYZE [table_name] - [ WHERE [ STATE = [ "PENDING" | "RUNNING" | "FINISHED" | "FAILED" ] ] ]; +```SQL +mysql> KILL ANALYZE 52357; ``` -Automatic collection tasks do not support viewing the completion status and failure reasons for each column individually. By default, it only retains the status of the last 20,000 completed automatic collection tasks. - -## Configuration Options +
-| fe conf option | comment | default value | -|---------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------| -| statistics_sql_parallel_exec_instance_num | Controls the number of concurrent instances/pipeline tasks for each statistics collection SQL on the BE side. | 1 | -| statistics_sql_mem_limit_in_bytes | Controls the amount of BE memory that each statistics collection SQL can use. | 2L * 1024 * 1024 * 1024 (2GiB) | -| statistics_simultaneously_running_task_num | After submitting asynchronous jobs using `ANALYZE TABLE[DATABASE]`, this parameter limits the number of columns that can be analyzed simultaneously. All asynchronous tasks are collectively constrained by this parameter. | 5 | -| analyze_task_timeout_in_minutes | Timeout for AnalyzeTask execution. | 12 hours | -| stats_cache_size| The actual memory usage of statistics cache depends heavily on the characteristics of the data because the average size of maximum/minimum values and the number of buckets in histograms can vary greatly in different datasets and scenarios. Additionally, factors like JVM versions can also affect it. Below is the memory size occupied by statistics cache with 100,000 items. The average length of maximum/minimum values per item is 32, the average length of column names is 16, and the statistics cache occupies a total of 61.2777404785MiB of memory. It is strongly discouraged to analyze columns with very large string values as this may lead to FE memory overflow. | 100000 | -|enable_auto_sample|Enable automatic sampling for large tables. When enabled, statistics will be automatically collected through sampling for tables larger than the `huge_table_lower_bound_size_in_bytes` threshold.| false| -|auto_analyze_job_record_count|Controls the persistence of records for automatically triggered statistics collection jobs.|20000| -|huge_table_default_sample_rows|Defines the number of sample rows for large tables when automatic sampling is enabled.|4194304| -|huge_table_lower_bound_size_in_bytes|Defines the lower size threshold for large tables. When `enable_auto_sample` is enabled, statistics will be automatically collected through sampling for tables larger than this value.|5368 709120| -|huge_table_auto_analyze_interval_in_millis|Controls the minimum time interval for automatic ANALYZE on large tables. Within this interval, tables larger than `huge_table_lower_bound_size_in_bytes` will only be analyzed once.|43200000| -|table_stats_health_threshold|Takes a value between 0-100. When the data update volume reaches (100 - table_stats_health_threshold)% since the last statistics collection operation, the statistics for the table are considered outdated.|80| -|Session Variable|Description|Default Value| -|---|---|---| -|full_auto_analyze_start_time|Start time for automatic statistics collection|00:00:00| -|full_auto_analyze_end_time|End time for automatic statistics collection|02:00:00| -|enable_full_auto_analyze|Enable automatic collection functionality|true| +```markdown +## 3. Session Variables and Configuration Options -ATTENTION: The session variables listed above must be set globally using SET GLOBAL. +--- -## Usage Recommendations +### 3.1 Session Variables -Based on our testing, on tables with data size (i.e., actual storage space) below 128GiB, there is usually no need to modify the default configuration settings unless it is necessary to avoid resource contention during peak business hours by adjusting the execution time of the automatic collection feature. +| Session Variable | Description | Default Value | +| ----------------------------- | -------------------------------------------- | ------------- | +| full_auto_analyze_start_time | Start time for automatic statistics collection | 00:00:00 | +| full_auto_analyze_end_time | End time for automatic statistics collection | 23:59:59 | +| enable_full_auto_analyze | Enable automatic collection functionality | true | +| huge_table_default_sample_rows | Sampling rows for large tables | 4194304 | +| huge_table_lower_bound_size_in_bytes | Tables with size greater than this value will be automatically sampled during collection of statistics | 5368709120 | +| huge_table_auto_analyze_interval_in_millis | Controls the minimum time interval for automatic ANALYZE on large tables. Tables with sizes greater than `huge_table_lower_bound_size_in_bytes * 5` will be ANALYZEed only once within this time interval. | 43200000 | +| table_stats_health_threshold | Ranges from 0 to 100. If data updates since the last statistics collection exceed `(100 - table_stats_health_threshold)%`, the table's statistics are considered outdated. | 60 | +| analyze_timeout | Controls the timeout for synchronous ANALYZE in seconds | 43200 | -Depending on the cluster configuration, automatic collection tasks typically consume around 20% of CPU resources. Therefore, users should adjust the execution time of the automatic collection feature to avoid resource contention during peak business hours, depending on their specific business needs. +
-Since ANALYZE is a resource-intensive operation, it is best to avoid executing such operations during peak business hours to prevent disruption to the business. Additionally, in cases of high cluster load, ANALYZE operations are more likely to fail. Furthermore, it is advisable to avoid performing full ANALYZE on the entire database or table. Typically, it is sufficient to perform ANALYZE on columns that are frequently used as predicate conditions, in JOIN conditions, as aggregation fields, or as ID fields. If a user's SQL queries involve a large number of such operations and the table has no statistics or very outdated statistics, we recommend: +### 3.2 FE Configuration Options -* Performing ANALYZE on the columns involved in complex queries before submitting the complex query, as poorly planned complex queries can consume a significant amount of system resources and may lead to resource exhaustion or timeouts. -* If you have configured periodic data import routines for Doris, it is recommended to execute ANALYZE after the data import is complete to ensure that subsequent query planning can use the most up-to-date statistics. You can automate this setting using Doris's existing job scheduling framework. -* When significant changes occur in the table's data, such as creating a new table and completing data import, it is recommended to run ANALYZE on the corresponding table. +The following FE configuration options are typically not a major concern: -## Common Issues +| FE Configuration Option | Description | Default Value | +| ---------------------------------- | ---------------------------------------- | ------------- | +| analyze_record_limit | Controls the persistence of statistics job execution records | 20000 | +| stats_cache_size | FE-side statistics cache entries | 500,000 | +| statistics_simultaneously_running_task_num | Number of asynchronous jobs that can run simultaneously | 3 | +| statistics_sql_mem_limit_in_bytes | Controls the amount of BE memory each statistics SQL can use | 2,147,483,648 bytes (2 GiB) | -### ANALYZE WITH SYNC Execution Failed: Failed to analyze following columns... +
+``` -The SQL execution time is controlled by the `query_timeout` session variable, which has a default value of 300 seconds. Statements like `ANALYZE DATABASE/TABLE` often take longer, easily exceeding this time limit and being canceled. It is recommended to increase the value of `query_timeout` based on the data volume of the ANALYZE object. +## 4. Common Issues -### ANALYZE Submission Error: Stats table not available... +### 4.1 ANALYZE Submission Error: Stats table not available... When ANALYZE is executed, statistics data is written to the internal table `__internal_schema.column_statistics`. FE checks the tablet status of this table before executing ANALYZE. If there are unavailable tablets, the task is rejected. Please check the BE cluster status if this error occurs. Users can use `SHOW BACKENDS\G` to verify the BE (Backend) status. If the BE status is normal, you can use the command `ADMIN SHOW REPLICA STATUS FROM __internal_schema.[tbl_in_this_db]` to check the tablet status within this database, ensuring that the tablet status is also normal. -### Failure of ANALYZE on Large Tables +### 4.2 Failure of ANALYZE on Large Tables Due to resource limitations, ANALYZE on some large tables may timeout or exceed BE memory limits. In such cases, it is recommended to use `ANALYZE ... WITH SAMPLE...`. - diff --git a/docs/zh-CN/docs/query-acceleration/statistics.md b/docs/zh-CN/docs/query-acceleration/statistics.md index d9aac9b678014d..7700ae3db44f02 100644 --- a/docs/zh-CN/docs/query-acceleration/statistics.md +++ b/docs/zh-CN/docs/query-acceleration/statistics.md @@ -26,7 +26,6 @@ under the License. # 统计信息 - 通过收集统计信息有助于优化器了解数据分布特性,在进行CBO(基于成本优化)时优化器会利用这些统计信息来计算谓词的选择性,并估算每个执行计划的成本。从而选择更优的计划以大幅提升查询效率。 当前收集列的如下信息: @@ -41,17 +40,21 @@ under the License. | `max` | 最⼤值 | | `null_count` | 空值数量 | -## 收集统计信息 +
+ + +## 1. 收集统计信息 + +--- -### 使用ANALYZE语句 +### 1.1 使用ANALYZE语句手动收集 -Doris支持用户通过提交ANALYZE语句来触发统计信息的收集和更新。 +Doris支持用户通过提交ANALYZE语句来手动触发统计信息的收集和更新。 语法: ```SQL ANALYZE < TABLE | DATABASE table_name | db_name > - [ PARTITIONS [(*) | (partition_name [, ...]) | WITH RECENT COUNT ] ] [ (column_name [, ...]) ] [ [ WITH SYNC ] [ WITH SAMPLE PERCENT | ROWS ] [ WITH SQL ] ] [ PROPERTIES ("key" = "value", ...) ]; @@ -59,61 +62,109 @@ ANALYZE < TABLE | DATABASE table_name | db_name > 其中: -- table_name: 指定的的目标表。可以是  `db_name.table_name`  形式。 -- partition_name: 指定的目标分区(目前只针对Hive外表)。必须是  `table_name`  中存在的分区,多个列名称用逗号分隔。分区名样例: 单层分区PARTITIONS(`event_date=20230706`),多层分区PARTITIONS(`nation=CN/city=Beijing`)。PARTITIONS (*)指定所有分区,PARTITIONS WITH RECENT 100指定最新的100个分区。 +- table_name: 指定的目标表。可以是  `db_name.table_name`  形式。 - column_name: 指定的目标列。必须是  `table_name`  中存在的列,多个列名称用逗号分隔。 -- sync:同步收集统计信息。收集完后返回。若不指定则异步执行并返回任务 ID。 +- sync:同步收集统计信息。收集完后返回。若不指定则异步执行并返回JOB ID。 - sample percent | rows:抽样收集统计信息。可以指定抽样比例或者抽样行数。 - sql:执行sql来收集外表分区列统计信息。默认从元数据收集分区列信息,这样效率比较高但是行数和数据量大小可能不准。用户可以指定使用sql来收集,这样可以收集到准确的分区列信息。 -### 自动收集 +下面是一些例子 -用户可以通过设置FE配置项`enable_full_auto_analyze = true`来启用本功能。开启后,将在指定的时间段内自动收集满足条件的库表上的统计信息。用户可以通过设置参数`full_auto_analyze_start_time`(默认为00:00:00)和参数`full_auto_analyze_end_time`(默认为02:00:00)来指定自动收集的时间段。 +对一张表按照10%的比例采样收集统计数据: -此功能仅对没有统计信息或者统计信息过时的库表进行收集。当一个表的数据更新了20%(该值可通过参数`table_stats_health_threshold`(默认为80)配置)以上时,Doris会认为该表的统计信息已经过时。 +```sql +ANALYZE TABLE lineitem WITH SAMPLE PERCENT 10; +``` + +对一张表按采样10万行收集统计数据 -对于数据量较大(默认为5GiB)的表,Doris会自动采取采样的方式去收集,以尽可能降低对系统造成的负担并尽快完成收集作业,用户可通过设置FE参数`huge_table_lower_bound_size_in_bytes`来调节此行为。如果希望对所有的表都采取全量收集,可配置FE参数`enable_auto_sample`为false。同时对于数据量大于`huge_table_lower_bound_size_in_bytes`的表,Doris保证其收集时间间隔不小于12小时(该时间可通过FE参数`huge_table_auto_analyze_interval_in_millis`控制)。 +```sql +ANALYZE TABLE lineitem WITH SAMPLE ROWS 100000; +``` -自动采样默认采样4194304(2^22)行,但由于实现方式的原因实际采样数可能大于该值。如果希望采样更多的行以获得更准确的数据分布信息,可通过FE参数`huge_table_default_sample_rows`配置。 +
-### 任务管理 +### 1.2 自动收集 -#### 查看统计任务 +此功能从2.0.3开始正式支持,默认为全天开启状态。下面对其基本运行逻辑进行阐述,在每次导入事务提交后,Doris将记录本次导入事务更新的表行数用以估算当前已有表的统计数据的健康度(对于没有收集过统计数据的表,其健康度为0)。当表的健康度低于60(可通过参数`table_stats_health_threshold`调节)时,Doris会认为该表的统计信息已经过时,并在之后触发对该表的统计信息收集作业。而对于统计信息健康度高于60的表,则不会重复进行收集。 -通过 `SHOW ANALYZE` 来查看统计信息收集任务的信息。 +统计信息的收集作业本身需要占用一定的系统资源,为了尽可能降低开销,对于数据量较大(默认为5GiB,可通过设置FE参数`huge_table_lower_bound_size_in_bytes`来调节此行为)的表,Doris会自动采取采样的方式去收集,自动采样默认采样4194304(2^22)行,以尽可能降低对系统造成的负担并尽快完成收集作业。如果希望采样更多的行以获得更准确的数据分布信息,可通过调整参数`huge_table_default_sample_rows`增大采样行数。另外对于数据量大于`huge_table_lower_bound_size_in_bytes` * 5 的表,Doris保证其收集时间间隔不小于12小时(该时间可通过调整参数`huge_table_auto_analyze_interval_in_millis`控制)。 + +如果担心自动收集作业对业务造成干扰,可结合自身需求通过设置参数`full_auto_analyze_start_time`和参数`full_auto_analyze_end_time`指定自动收集作业在业务负载较低的时间段执行。也可以通过设置参数`enable_full_auto_analyze` 为`false`来彻底关闭本功能。 + +
+ +## 2. 作业管理 + +--- + +### 2.1 查看统计作业 + +通过 `SHOW ANALYZE` 来查看统计信息收集作业的信息。 语法如下: ```SQL -SHOW ANALYZE < table_name | job_id > +SHOW [AUTO] ANALYZE < table_name | job_id > [ WHERE [ STATE = [ "PENDING" | "RUNNING" | "FINISHED" | "FAILED" ] ] ]; ``` -- table_name:表名,指定后可查看该表对应的统计任务信息。可以是  `db_name.table_name`  形式。不指定时返回所有统计任务信息。 -- job_id:统计信息任务 ID,执行 `ANALYZE` 非同步收集统计信息时所返回的值。不指定时返回所有统计任务信息。 +- AUTO:仅仅展示自动收集历史作业信息。需要注意的是默认只保存过去20000个执行完毕的自动收集作业的状态。 +- table_name:表名,指定后可查看该表对应的统计作业信息。可以是  `db_name.table_name`  形式。不指定时返回所有统计作业信息。 +- job_id:统计信息作业 ID,执行 `ANALYZE` 异步收集时得到。不指定id时此命令返回所有统计作业信息。 输出: | 列名 | 说明 | | :--------------------- | :----------- | -| `job_id` | 统计任务 ID | +| `job_id` | 统计作业 ID | | `catalog_name` | catalog 名称 | | `db_name` | 数据库名称 | | `tbl_name` | 表名称 | -| `col_name` | 列名称 | -| `job_type` | 任务类型 | +| `col_name` | 列名称列表 | +| `job_type` | 作业类型 | | `analysis_type` | 统计类型 | -| `message` | 任务信息 | +| `message` | 作业信息 | | `last_exec_time_in_ms` | 上次执行时间 | -| `state` | 任务状态 | +| `state` | 作业状态 | | `schedule_type` | 调度方式 | +下面是一个例子: -可通过`SHOW ANALYZE TASK STATUS [job_id]`,查看具体每个列统计信息的收集完成情况。 +```sql +mysql> show analyze 245073\G; +*************************** 1. row *************************** + job_id: 245073 + catalog_name: internal + db_name: default_cluster:tpch + tbl_name: lineitem + col_name: [l_returnflag,l_receiptdate,l_tax,l_shipmode,l_suppkey,l_shipdate,l_commitdate,l_partkey,l_orderkey,l_quantity,l_linestatus,l_comment,l_extendedprice,l_linenumber,l_discount,l_shipinstruct] + job_type: MANUAL + analysis_type: FUNDAMENTALS + message: +last_exec_time_in_ms: 2023-11-07 11:00:52 + state: FINISHED + progress: 16 Finished | 0 Failed | 0 In Progress | 16 Total + schedule_type: ONCE +``` + +
+ +### 2.2 查看每列统计信息收集情况 + +每个收集作业中可以包含一到多个任务,每个任务对应一列的收集。用户可通过如下命令查看具体每列的统计信息收集完成情况。 + +语法: + +```sql +SHOW ANALYZE TASK STATUS [job_id] +``` + +下面是一个例子: ``` -mysql> show analyze task status 20038 ; +mysql> show analyze task status 20038 ; +---------+----------+---------+----------------------+----------+ | task_id | col_name | message | last_exec_time_in_ms | state | +---------+----------+---------+----------------------+----------+ @@ -126,34 +177,50 @@ mysql> show analyze task status 20038 ; ``` -#### 终止统计任务 +
-通过 `KILL ANALYZE` 来终止正在运行的统计任务。 +### 2.3 查看列统计信息 + +通过 `SHOW COLUMN STATS` 来查看列的各项统计数据。 语法如下: ```SQL -KILL ANALYZE job_id; +SHOW COLUMN [cached] STATS table_name [ (column_name [, ...]) ]; ``` 其中: -- job_id:统计信息任务 ID。执行 `ANALYZE` 非同步收集统计信息时所返回的值,也可以通过 `SHOW ANALYZE` 语句获取。 +- cached: 展示当前FE内存缓存中的统计信息。 +- table_name: 收集统计信息的目标表。可以是  `db_name.table_name`  形式。 +- column_name: 指定的目标列,必须是  `table_name`  中存在的列,多个列名称用逗号分隔。 -示例: +下面是一个例子: -- 终止 ID 为 52357 的统计任务。 +```sql +mysql> show column stats lineitem(l_tax)\G; +*************************** 1. row *************************** + column_name: l_tax + count: 6001215.0 + ndv: 9.0 + num_null: 0.0 + data_size: 4.800972E7 +avg_size_byte: 8.0 + min: 0.00 + max: 0.08 + method: FULL + type: FUNDAMENTALS + trigger: MANUAL + query_times: 0 + updated_time: 2023-11-07 11:00:46 -```SQL -mysql> KILL ANALYZE 52357; ``` -#### 查看统计信息 - -#### 表统计信息 +
+### 2.4 表收集概况 -通过 `SHOW TABLE STATS` 表的统计信息收集概况。 +通过 `SHOW TABLE STATS` 查看表的统计信息收集概况。 语法如下: @@ -163,128 +230,102 @@ SHOW TABLE STATS table_name; 其中: -- table_name: 导入数据的目标表。可以是  `db_name.table_name`  形式。 +- table_name: 目标表表名。可以是  `db_name.table_name`  形式。 输出: | 列名 | 说明 | | :------------------ | :--------------------- | -| `row_count` | 行数(不反映命令执行时的准确行数) | -| `method` | 收集方式(全量/采样) | -| `type` | 统计数据的类型 | -| `updated_time` | 上次更新时间 | -| `columns` | 收集过统计信息的列 | -| `trigger` | 统计信息收集触发方式(系统自动触发/用户触发) | - +|`updated_rows`|自上次ANALYZE以来该表的更新行数| +|`query_times`|保留列,后续版本用以记录该表查询次数| +|`row_count`| 行数(不反映命令执行时的准确行数)| +|`updated_time`| 上次更新时间| +|`columns`| 收集过统计信息的列| +|`trigger`|触发方式| -#### 查看列统计信息 +下面是一个例子: -通过 `SHOW COLUMN STATS` 来查看列的不同值数以及 `NULL` 数量等信息。 - -语法如下: - -```SQL -SHOW COLUMN [cached] STATS table_name [ (column_name [, ...]) ]; +```sql +mysql> show table stats lineitem \G; +*************************** 1. row *************************** +updated_rows: 0 + query_times: 0 + row_count: 6001215 +updated_time: 2023-11-07 + columns: [l_returnflag, l_receiptdate, l_tax, l_shipmode, l_suppkey, l_shipdate, l_commitdate, l_partkey, l_orderkey, l_quantity, l_linestatus, l_comment, l_extendedprice, l_linenumber, l_discount, l_shipinstruct] + trigger: MANUAL ``` -其中: +
-- cached: 展示当前FE内存缓存中的统计信息。 -- table_name: 收集统计信息的目标表。可以是  `db_name.table_name`  形式。 -- column_name: 指定的目标列,必须是  `table_name`  中存在的列,多个列名称用逗号分隔。 +### 2.5 终止统计作业 -#### 修改统计信息 +通过 `KILL ANALYZE` 来终止正在运行的统计作业。 -⽤户可以通过 `ALTER` 语句调整统计信息。 +语法如下: ```SQL -ALTER TABLE table_name MODIFY COLUMN column_name SET STATS ('stat_name' = 'stat_value', ...) [ PARTITION (partition_name) ]; +KILL ANALYZE job_id; ``` 其中: -- table_name: 删除统计信息的目标表。可以是 `db_name.table_name` 形式。 -- column_name: 指定的目标列,必须是 `table_name` 中存在的列,每次只能修改一列的统计信息。 -- stat_name 和 stat_value: 相应的统计信息名称和统计信息信息的值,多个统计信息逗号分隔。可以修改的统计信息包括 `row_count`, `ndv`, `num_nulls`, `min_value`, `max_value`, `data_size`。 - -#### 删除统计信息 +- job_id:统计信息作业 ID。执行 `ANALYZE` 异步收集统计信息时所返回的值,也可以通过 `SHOW ANALYZE` 语句获取。 -⽤户通过 `DROP` 语句删除统计信息,根据提供的参数,删除指定的表、分区或列的统计信息。删除时会同时删除列统计信息和列直方图信息。 +示例: -语法: +- 终止 ID 为 52357 的统计作业。 ```SQL -DROP [ EXPIRED ] STATS [ table_name [ (column_name [, ...]) ] ]; -``` - - -#### 删除Analyze Job - -用于根据job id删除自动/周期Analyze作业 - -```sql -DROP ANALYZE JOB [JOB_ID] +mysql> KILL ANALYZE 52357; ``` -### 查看自动收集任务执行情况 - -此命令用于打开自动收集功能后,查看自动收集任务的完成状态。 - -```sql -SHOW AUTO ANALYZE [ptable_name] - [ WHERE [ STATE = [ "PENDING" | "RUNNING" | "FINISHED" | "FAILED" ] ] ]; -``` +
-自动收集任务不支持查看每个列的具完成情况及失败原因。默认只保存过去20000个执行完毕的自动收集任务的状态。 +## 3. 会话变量及配置项 -## 配置项 +--- -|fe conf option | comment | default value | -|---------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------| -| statistics_sql_parallel_exec_instance_num | 控制每个统计信息收集SQL在BE侧的并发实例数/pipeline task num | 1 | -| statistics_sql_mem_limit_in_bytes | 控制每个统计信息SQL可占用的BE内存 | 2L * 1024 * 1024 * 1024 (2GiB) | -| statistics_simultaneously_running_task_num | 通过`ANALYZE TABLE[DATABASE]`提交异步作业后,可同时analyze的列的数量,所有异步任务共同受到该参数约束 | 5 | -| analyze_task_timeout_in_minutes | AnalyzeTask执行超时时间 | 12 hours | -|stats_cache_size| 统计信息缓存的实际内存占用大小高度依赖于数据的特性,因为在不同的数据集和场景中,最大/最小值的平均大小和直方图的桶数量会有很大的差异。此外,JVM版本等因素也会对其产生影响。下面给出统计信息缓存在包含100000个项目时所占用的内存大小。每个项目的最大/最小值的平均长度为32,列名的平均长度为16,统计信息缓存总共占用了61.2777404785MiB的内存。强烈不建议分析具有非常大字符串值的列,因为这可能导致FE内存溢出。 | 100000 | -|enable_auto_sample|是否开启大表自动sample,开启后对于大小超过huge_table_lower_bound_size_in_bytes会自动通过采样收集| false| -|auto_analyze_job_record_count|控制统计信息的自动触发作业执行记录的持久化行数|20000| -|huge_table_default_sample_rows|定义开启开启大表自动sample后,对大表的采样行数|4194304| -|huge_table_lower_bound_size_in_bytes|定义大表的大小下界,在开启enable_auto_sample的情况下,大小超过该值的表将会自动通过采样收集统计信息|5368 709120| -|huge_table_auto_analyze_interval_in_millis|控制对大表的自动ANALYZE的最小时间间隔,在该时间间隔内大小超过huge_table_lower_bound_size_in_bytes的表仅ANALYZE一次|43200000| -|table_stats_health_threshold|取值在0-100之间,当自上次统计信息收集操作之后,数据更新量达到 (100 - table_stats_health_threshold)% ,认为该表的统计信息已过时|80| +### 3.1 会话变量 |会话变量|说明|默认值| |---|---|---| |full_auto_analyze_start_time|自动统计信息收集开始时间|00:00:00| -|full_auto_analyze_end_time|自动统计信息收集结束时间|02:00:00| +|full_auto_analyze_end_time|自动统计信息收集结束时间|23:59:59| |enable_full_auto_analyze|开启自动收集功能|true| +|huge_table_default_sample_rows|对大表的采样行数|4194304| +|huge_table_lower_bound_size_in_bytes|大小超过该值的的表,在自动收集时将会自动通过采样收集统计信息|5368709120| +|huge_table_auto_analyze_interval_in_millis|控制对大表的自动ANALYZE的最小时间间隔,在该时间间隔内大小超过huge_table_lower_bound_size_in_bytes * 5的表仅ANALYZE一次|43200000| +|table_stats_health_threshold|取值在0-100之间,当自上次统计信息收集操作之后,数据更新量达到 (100 - table_stats_health_threshold)% ,认为该表的统计信息已过时|60| +|analyze_timeout|控制ANALYZE超时时间,单位为秒|43200| -注意:上面列出的会话变量必须通过`SET GLOBAL`全局设置。 - -## 使用建议 +
-根据我们的测试,在数据量(这里指实际存储占用的空间)为128GiB以下的表上,除自动收集功能执行时间段之外无须改动默认配置。 +### 3.2 FE配置项 -依据集群配置情况,自动收集任务通常会占用20%左右的CPU资源,因此用户需要根据自己的业务情况,适当调整自动收集功能执行时间段以避开业务高峰期资源抢占。 +下面的FE配置项通常情况下,无需关注 -由于ANALYZE是资源密集型操作,因此最好尽可能不要在业务高峰期执行此类操作,从而避免对业务造成干扰,集群负载较高的情况下,ANALYZE操作也更容易失败。此外,基于相同的原因,我们建议用户避免全量的ANALYZE整库整表。通常来讲,只需要对经常作为谓词条件,JOIN条件,聚合字段以及ID字段的列进行ANALYZE就足够了。如果用户提交的SQL涉及到大量此类操作,并且表上也没有统计信息或者统计信息非常陈旧,那么我们建议: - -* 在提交复杂查询之前先对涉及到的表列进行ANALYZE,因为规划不当的复杂查询将占用非常多的系统资源,非荣容易资源耗尽或超时而失败 -* 如果用户为Doris配置了周期性数据导入例程,那么建议在导入完毕后,执行ANALYZE从而保证后续查询规划能够利用到最新的统计数据。可以利用Doris已有的作业调度框架自动化完成此类设置 -* 当表的数据发生显著变化后,比如新建表并完成数据导入后,ANALYZE对应的表。 +|FE配置项|说明|默认值| +|---|---|---| +|analyze_record_limit|控制统计信息作业执行记录的持久化行数|20000| +|stats_cache_size| FE侧统计信息缓存条数 | 500000 | +| statistics_simultaneously_running_task_num |可同时执行的异步作业数量|3| +| statistics_sql_mem_limit_in_bytes| 控制每个统计信息SQL可占用的BE内存| 2L * 1024 * 1024 * 1024 (2GiB) | -## 常见问题 +
-### ANALYZE WITH SYNC 执行失败:Failed to analyze following columns... +## 4. 常见问题 -SQL执行时间受`query_timeout`会话变量控制,该变量默认值为300秒,`ANALYZE DATABASE/TABLE`等语句通常耗时较大,很容易超过该时间限制而被cancel,建议根据ANALYZE对象的数据量适当增大`query_timeout`的值。 +--- -### ANALYZE提交报错:Stats table not available... +### 4.1 ANALYZE提交报错:Stats table not available... -执行ANALYZE时统计数据会被写入到内部表`__internal_schema.column_statistics`中,FE会在执行ANALYZE前检查该表tablet状态,如果存在不可用的tablet则拒绝执行任务。出现该报错请检查BE集群状态。 +执行ANALYZE时统计数据会被写入到内部表`__internal_schema.column_statistics`中,FE会在执行ANALYZE前检查该表tablet状态,如果存在不可用的tablet则拒绝执行作业。出现该报错请检查BE集群状态。 用户可通过`SHOW BACKENDS\G`,确定BE状态是否正常。如果BE状态正常,可使用命令`ADMIN SHOW REPLICA STATUS FROM __internal_schema.[tbl_in_this_db]`,检查该库下tablet状态,确保tablet状态正常。 -### 大表ANALYZE失败 +
+ +### 4.2 大表ANALYZE失败 由于ANALYZE能够使用的资源受到比较严格的限制,对一些大表的ANALYZE操作有可能超时或者超出BE内存限制。这些情况下,建议使用 `ANALYZE ... WITH SAMPLE...`。 diff --git a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java index 2d02a2632b8696..c6970c7d17067e 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java +++ b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java @@ -17,8 +17,6 @@ package org.apache.doris.common; -import java.util.concurrent.TimeUnit; - public class Config extends ConfigBase { @ConfField(description = {"用户自定义配置文件的路径,用于存放 fe_custom.conf。该文件中的配置会覆盖 fe.conf 中的配置", @@ -1761,7 +1759,7 @@ public class Config extends ConfigBase { * Used to determined how many statistics collection SQL could run simultaneously. */ @ConfField - public static int statistics_simultaneously_running_task_num = 5; + public static int statistics_simultaneously_running_task_num = 3; /** * if table has too many replicas, Fe occur oom when schema change. @@ -2068,7 +2066,7 @@ public class Config extends ConfigBase { * FE OOM. */ @ConfField - public static long stats_cache_size = 10_0000; + public static long stats_cache_size = 50_0000; /** * This configuration is used to enable the statistics of query information, which will record @@ -2091,9 +2089,6 @@ public class Config extends ConfigBase { "Whether to enable binlog feature"}) public static boolean enable_feature_binlog = false; - @ConfField - public static int analyze_task_timeout_in_hours = 12; - @ConfField(mutable = true, masterOnly = true, description = { "是否禁止使用 WITH REOSOURCE 语句创建 Catalog。", "Whether to disable creating catalog with WITH RESOURCE statement."}) @@ -2159,9 +2154,6 @@ public class Config extends ConfigBase { @ConfField public static boolean forbid_running_alter_job = false; - @ConfField - public static int table_stats_health_threshold = 80; - @ConfField(description = { "暂时性配置项,开启后会自动将所有的olap表修改为可light schema change", "temporary config filed, will make all olap tables enable light schema change" @@ -2188,28 +2180,6 @@ public class Config extends ConfigBase { + "but it will increase the memory overhead."}) public static int virtual_node_number = 2048; - @ConfField(description = {"控制对大表的自动ANALYZE的最小时间间隔," - + "在该时间间隔内大小超过huge_table_lower_bound_size_in_bytes的表仅ANALYZE一次", - "This controls the minimum time interval for automatic ANALYZE on large tables. Within this interval," - + "tables larger than huge_table_lower_bound_size_in_bytes are analyzed only once."}) - public static long huge_table_auto_analyze_interval_in_millis = TimeUnit.HOURS.toMillis(12); - - @ConfField(description = {"定义大表的大小下界,在开启enable_auto_sample的情况下," - + "大小超过该值的表将会自动通过采样收集统计信息", "This defines the lower size bound for large tables. " - + "When enable_auto_sample is enabled, tables larger than this value will automatically collect " - + "statistics through sampling"}) - public static long huge_table_lower_bound_size_in_bytes = 5L * 1024 * 1024 * 1024; - - @ConfField(description = {"定义开启开启大表自动sample后,对大表的采样比例", - "This defines the number of sample percent for large tables when automatic sampling for" - + "large tables is enabled"}) - public static int huge_table_default_sample_rows = 4194304; - - @ConfField(description = {"是否开启大表自动sample,开启后对于大小超过huge_table_lower_bound_size_in_bytes会自动通过采样收集" - + "统计信息", "Whether to enable automatic sampling for large tables, which, when enabled, automatically" - + "collects statistics through sampling for tables larger than 'huge_table_lower_bound_size_in_bytes'"}) - public static boolean enable_auto_sample = false; - @ConfField(description = { "控制统计信息的自动触发作业执行记录的持久化行数", "Determine the persist number of automatic triggered analyze job execution status" diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java index 1cbdcc12a192f4..8c028bc8fc9199 100755 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Env.java @@ -230,7 +230,6 @@ import org.apache.doris.statistics.StatisticsAutoCollector; import org.apache.doris.statistics.StatisticsCache; import org.apache.doris.statistics.StatisticsCleaner; -import org.apache.doris.statistics.StatisticsPeriodCollector; import org.apache.doris.statistics.query.QueryStats; import org.apache.doris.system.Backend; import org.apache.doris.system.Frontend; @@ -495,8 +494,6 @@ public class Env { private StatisticsAutoCollector statisticsAutoCollector; - private StatisticsPeriodCollector statisticsPeriodCollector; - private HiveTransactionMgr hiveTransactionMgr; private TopicPublisherThread topicPublisherThread; @@ -720,7 +717,6 @@ private Env(boolean isCheckpointCatalog) { this.analysisManager = new AnalysisManager(); this.statisticsCleaner = new StatisticsCleaner(); this.statisticsAutoCollector = new StatisticsAutoCollector(); - this.statisticsPeriodCollector = new StatisticsPeriodCollector(); this.globalFunctionMgr = new GlobalFunctionMgr(); this.workloadGroupMgr = new WorkloadGroupMgr(); this.queryStats = new QueryStats(); @@ -971,9 +967,6 @@ public void initialize(String[] args) throws Exception { if (statisticsAutoCollector != null) { statisticsAutoCollector.start(); } - if (statisticsPeriodCollector != null) { - statisticsPeriodCollector.start(); - } queryCancelWorker.start(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java index 16cec127bff256..d9501f0f1d4a8e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java @@ -54,7 +54,6 @@ import org.apache.doris.statistics.AnalysisInfo.AnalysisType; import org.apache.doris.statistics.BaseAnalysisTask; import org.apache.doris.statistics.HistogramTask; -import org.apache.doris.statistics.MVAnalysisTask; import org.apache.doris.statistics.OlapAnalysisTask; import org.apache.doris.statistics.TableStatsMeta; import org.apache.doris.statistics.util.StatisticsUtil; @@ -1122,11 +1121,9 @@ public TTableDescriptor toThrift() { public BaseAnalysisTask createAnalysisTask(AnalysisInfo info) { if (info.analysisType.equals(AnalysisType.HISTOGRAM)) { return new HistogramTask(info); - } - if (info.analysisType.equals(AnalysisType.FUNDAMENTALS)) { + } else { return new OlapAnalysisTask(info); } - return new MVAnalysisTask(info); } public boolean needReAnalyzeTable(TableStatsMeta tblStats) { @@ -1146,7 +1143,7 @@ public boolean needReAnalyzeTable(TableStatsMeta tblStats) { } long updateRows = tblStats.updatedRows.get(); int tblHealth = StatisticsUtil.getTableHealth(rowCount, updateRows); - return tblHealth < Config.table_stats_health_threshold; + return tblHealth < StatisticsUtil.getTableStatsHealthThreshold(); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java index 0fad8ea1d1a9ec..61e75387740f85 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/stats/StatsCalculator.java @@ -569,6 +569,10 @@ private Statistics computeFilter(Filter filter) { } private ColumnStatistic getColumnStatistic(TableIf table, String colName) { + ConnectContext connectContext = ConnectContext.get(); + if (connectContext != null && connectContext.getSessionVariable().internalSession) { + return ColumnStatistic.UNKNOWN; + } long catalogId; long dbId; try { diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java index 1bf6791298b626..9cb2b5edc84e56 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java @@ -62,6 +62,7 @@ import java.util.Map; import java.util.Random; import java.util.Set; +import java.util.concurrent.TimeUnit; /** * System variable. @@ -430,6 +431,17 @@ public class SessionVariable implements Serializable, Writable { public static final String ENABLE_DECIMAL256 = "enable_decimal256"; + public static final String STATS_INSERT_MERGE_ITEM_COUNT = "stats_insert_merge_item_count"; + + public static final String HUGE_TABLE_DEFAULT_SAMPLE_ROWS = "huge_table_default_sample_rows"; + public static final String HUGE_TABLE_LOWER_BOUND_SIZE_IN_BYTES = "huge_table_lower_bound_size_in_bytes"; + + public static final String HUGE_TABLE_AUTO_ANALYZE_INTERVAL_IN_MILLIS + = "huge_table_auto_analyze_interval_in_millis"; + + public static final String TABLE_STATS_HEALTH_THRESHOLD + = "table_stats_health_threshold"; + public static final List DEBUG_VARIABLES = ImmutableList.of( SKIP_DELETE_PREDICATE, SKIP_DELETE_BITMAP, @@ -486,7 +498,7 @@ public class SessionVariable implements Serializable, Writable { public int queryTimeoutS = 900; // query timeout in second. - @VariableMgr.VarAttr(name = ANALYZE_TIMEOUT, needForward = true) + @VariableMgr.VarAttr(name = ANALYZE_TIMEOUT, flag = VariableMgr.GLOBAL, needForward = true) public int analyzeTimeoutS = 43200; // The global max_execution_time value provides the default for the session value for new connections. @@ -1246,7 +1258,7 @@ public void setMaxJoinNumberOfReorder(int maxJoinNumberOfReorder) { description = {"该参数定义自动ANALYZE例程的结束时间", "This parameter defines the end time for the automatic ANALYZE routine."}, flag = VariableMgr.GLOBAL) - public String fullAutoAnalyzeEndTime = "02:00:00"; + public String fullAutoAnalyzeEndTime = "23:59:59"; @VariableMgr.VarAttr(name = SQL_DIALECT, needForward = true, checker = "checkSqlDialect", description = {"解析sql使用的方言", "The dialect used to parse sql."}) @@ -1276,6 +1288,48 @@ public void setMaxJoinNumberOfReorder(int maxJoinNumberOfReorder) { "the runtime filter id in IGNORE_RUNTIME_FILTER_IDS list will not be generated"}) public String ignoreRuntimeFilterIds = ""; + + @VariableMgr.VarAttr(name = STATS_INSERT_MERGE_ITEM_COUNT, flag = VariableMgr.GLOBAL, description = { + "控制统计信息相关INSERT攒批数量", "Controls the batch size for stats INSERT merging." + } + ) + public int statsInsertMergeItemCount = 200; + + @VariableMgr.VarAttr(name = HUGE_TABLE_DEFAULT_SAMPLE_ROWS, flag = VariableMgr.GLOBAL, description = { + "定义开启开启大表自动sample后,对大表的采样比例", + "This defines the number of sample percent for large tables when automatic sampling for" + + "large tables is enabled" + + }) + public long hugeTableDefaultSampleRows = 4194304; + + + @VariableMgr.VarAttr(name = HUGE_TABLE_LOWER_BOUND_SIZE_IN_BYTES, flag = VariableMgr.GLOBAL, + description = { + "大小超过该值的表将会自动通过采样收集统计信息", + "This defines the lower size bound for large tables. " + + "When enable_auto_sample is enabled, tables" + + "larger than this value will automatically collect " + + "statistics through sampling"}) + public long hugeTableLowerBoundSizeInBytes = 5L * 1024 * 1024 * 1024; + + @VariableMgr.VarAttr(name = HUGE_TABLE_AUTO_ANALYZE_INTERVAL_IN_MILLIS, flag = VariableMgr.GLOBAL, + description = {"控制对大表的自动ANALYZE的最小时间间隔," + + "在该时间间隔内大小超过huge_table_lower_bound_size_in_bytes的表仅ANALYZE一次", + "This controls the minimum time interval for automatic ANALYZE on large tables." + + "Within this interval," + + "tables larger than huge_table_lower_bound_size_in_bytes are analyzed only once."}) + public long hugeTableAutoAnalyzeIntervalInMillis = TimeUnit.HOURS.toMillis(12); + + @VariableMgr.VarAttr(name = TABLE_STATS_HEALTH_THRESHOLD, flag = VariableMgr.GLOBAL, + description = {"取值在0-100之间,当自上次统计信息收集操作之后" + + "数据更新量达到 (100 - table_stats_health_threshold)% ,认为该表的统计信息已过时", + "The value should be between 0 and 100. When the data update quantity " + + "exceeds (100 - table_stats_health_threshold)% since the last " + + "statistics collection operation, the statistics for this table are" + + "considered outdated."}) + public int tableStatsHealthThreshold = 60; + public static final String IGNORE_RUNTIME_FILTER_IDS = "ignore_runtime_filter_ids"; public Set getIgnoredRuntimeFilterIds() { diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisJob.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisJob.java new file mode 100644 index 00000000000000..904dc21e337732 --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisJob.java @@ -0,0 +1,193 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.statistics; + +import org.apache.doris.catalog.Env; +import org.apache.doris.qe.AuditLogHelper; +import org.apache.doris.qe.AutoCloseConnectContext; +import org.apache.doris.qe.QueryState; +import org.apache.doris.qe.QueryState.MysqlStateType; +import org.apache.doris.qe.StmtExecutor; +import org.apache.doris.statistics.util.StatisticsUtil; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.StringJoiner; + +public class AnalysisJob { + + public static final Logger LOG = LogManager.getLogger(AnalysisJob.class); + + protected Set queryingTask; + + protected Set queryFinished; + + protected List buf; + + protected int totalTaskCount; + + protected int queryFinishedTaskCount; + + protected StmtExecutor stmtExecutor; + + protected boolean killed; + + protected long start; + + protected AnalysisInfo jobInfo; + + protected AnalysisManager analysisManager; + + public AnalysisJob(AnalysisInfo jobInfo, Collection queryingTask) { + for (BaseAnalysisTask task : queryingTask) { + task.job = this; + } + this.queryingTask = new HashSet<>(queryingTask); + this.queryFinished = new HashSet<>(); + this.buf = new ArrayList<>(); + totalTaskCount = queryingTask.size(); + start = System.currentTimeMillis(); + this.jobInfo = jobInfo; + this.analysisManager = Env.getCurrentEnv().getAnalysisManager(); + } + + public synchronized void appendBuf(BaseAnalysisTask task, List statsData) { + queryingTask.remove(task); + buf.addAll(statsData); + queryFinished.add(task); + queryFinishedTaskCount += 1; + if (queryFinishedTaskCount == totalTaskCount) { + writeBuf(); + updateTaskState(AnalysisState.FINISHED, "Cost time in sec: " + + (System.currentTimeMillis() - start) / 1000); + deregisterJob(); + } else if (buf.size() >= StatisticsUtil.getInsertMergeCount()) { + writeBuf(); + } + } + + // CHECKSTYLE OFF + // fallthrough here is expected + public void updateTaskState(AnalysisState state, String msg) { + long time = System.currentTimeMillis(); + switch (state) { + case FAILED: + for (BaseAnalysisTask task : queryingTask) { + analysisManager.updateTaskStatus(task.info, state, msg, time); + task.cancel(); + } + killed = true; + case FINISHED: + for (BaseAnalysisTask task : queryFinished) { + analysisManager.updateTaskStatus(task.info, state, msg, time); + } + default: + // DO NOTHING + } + } + + protected void writeBuf() { + if (killed) { + return; + } + // buf could be empty when nothing need to do, for example user submit an analysis task for table with no data + // change + if (!buf.isEmpty()) { + String insertStmt = "INSERT INTO " + StatisticConstants.FULL_QUALIFIED_STATS_TBL_NAME + " VALUES "; + StringJoiner values = new StringJoiner(","); + for (ColStatsData data : buf) { + values.add(data.toSQL(true)); + } + insertStmt += values.toString(); + int retryTimes = 0; + while (retryTimes < StatisticConstants.ANALYZE_TASK_RETRY_TIMES) { + if (killed) { + return; + } + try (AutoCloseConnectContext r = StatisticsUtil.buildConnectContext(false)) { + stmtExecutor = new StmtExecutor(r.connectContext, insertStmt); + executeWithExceptionOnFail(stmtExecutor); + break; + } catch (Exception t) { + LOG.warn("Failed to write buf: " + insertStmt, t); + retryTimes++; + if (retryTimes >= StatisticConstants.ANALYZE_TASK_RETRY_TIMES) { + updateTaskState(AnalysisState.FAILED, t.getMessage()); + return; + } + } + } + } + updateTaskState(AnalysisState.FINISHED, ""); + syncLoadStats(); + queryFinished.clear(); + } + + protected void executeWithExceptionOnFail(StmtExecutor stmtExecutor) throws Exception { + if (killed) { + return; + } + LOG.debug("execute internal sql: {}", stmtExecutor.getOriginStmt()); + try { + stmtExecutor.execute(); + QueryState queryState = stmtExecutor.getContext().getState(); + if (queryState.getStateType().equals(MysqlStateType.ERR)) { + throw new RuntimeException( + "Failed to insert : " + stmtExecutor.getOriginStmt().originStmt + "Error msg: " + + queryState.getErrorMessage()); + } + } finally { + AuditLogHelper.logAuditLog(stmtExecutor.getContext(), stmtExecutor.getOriginStmt().toString(), + stmtExecutor.getParsedStmt(), stmtExecutor.getQueryStatisticsForAuditLog(), + true); + } + } + + public void taskFailed(BaseAnalysisTask task, String reason) { + updateTaskState(AnalysisState.FAILED, reason); + cancel(); + deregisterJob(); + } + + public void cancel() { + for (BaseAnalysisTask task : queryingTask) { + task.cancel(); + } + } + + public void deregisterJob() { + analysisManager.removeJob(jobInfo.jobId); + } + + protected void syncLoadStats() { + long tblId = jobInfo.tblId; + for (BaseAnalysisTask task : queryFinished) { + String colName = task.col.getName(); + if (!Env.getCurrentEnv().getStatisticsCache().syncLoadColStats(tblId, -1, colName)) { + analysisManager.removeColStatsStatus(tblId, colName); + } + } + } + +} diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java index ef6cafa1f3aa2d..e4b1b01fae8682 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisManager.java @@ -42,7 +42,6 @@ import org.apache.doris.common.ThreadPoolManager.BlockedPolicy; import org.apache.doris.common.io.Text; import org.apache.doris.common.io.Writable; -import org.apache.doris.common.util.Daemon; import org.apache.doris.common.util.Util; import org.apache.doris.datasource.CatalogIf; import org.apache.doris.mysql.privilege.PrivPredicate; @@ -101,7 +100,7 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -public class AnalysisManager extends Daemon implements Writable { +public class AnalysisManager implements Writable { private static final Logger LOG = LogManager.getLogger(AnalysisManager.class); @@ -113,11 +112,11 @@ public class AnalysisManager extends Daemon implements Writable { private AnalysisTaskExecutor taskExecutor; // Store task information in metadata. - private final NavigableMap analysisTaskInfoMap = + protected final NavigableMap analysisTaskInfoMap = Collections.synchronizedNavigableMap(new TreeMap<>()); // Store job information in metadata. - private final NavigableMap analysisJobInfoMap = + protected final NavigableMap analysisJobInfoMap = Collections.synchronizedNavigableMap(new TreeMap<>()); // Tracking system submitted job, keep in mem only @@ -128,6 +127,8 @@ public class AnalysisManager extends Daemon implements Writable { private final Map idToTblStats = new ConcurrentHashMap<>(); + private final Map idToAnalysisJob = new ConcurrentHashMap<>(); + protected SimpleQueue autoJobs = createSimpleQueue(null, this); private final Function userJobStatusUpdater = w -> { @@ -237,7 +238,6 @@ public class AnalysisManager extends Daemon implements Writable { new Function[] {userJobStatusUpdater, systemJobStatusUpdater}; public AnalysisManager() { - super(TimeUnit.SECONDS.toMillis(StatisticConstants.ANALYZE_MANAGER_INTERVAL_IN_SECS)); if (!Env.isCheckpointThread()) { this.taskExecutor = new AnalysisTaskExecutor(Config.statistics_simultaneously_running_task_num); this.statisticsCache = new StatisticsCache(); @@ -245,44 +245,6 @@ public AnalysisManager() { } } - @Override - protected void runOneCycle() { - clear(); - } - - private void clear() { - clearExpiredAnalysisInfo(analysisJobInfoMap, (a) -> - a.scheduleType.equals(ScheduleType.ONCE) - && System.currentTimeMillis() - a.lastExecTimeInMs - > TimeUnit.DAYS.toMillis(StatisticConstants.ANALYSIS_JOB_INFO_EXPIRATION_TIME_IN_DAYS), - (id) -> { - Env.getCurrentEnv().getEditLog().logDeleteAnalysisJob(new AnalyzeDeletionLog(id)); - return null; - }); - clearExpiredAnalysisInfo(analysisTaskInfoMap, (a) -> System.currentTimeMillis() - a.lastExecTimeInMs - > TimeUnit.DAYS.toMillis(StatisticConstants.ANALYSIS_JOB_INFO_EXPIRATION_TIME_IN_DAYS), - (id) -> { - Env.getCurrentEnv().getEditLog().logDeleteAnalysisTask(new AnalyzeDeletionLog(id)); - return null; - }); - } - - private void clearExpiredAnalysisInfo(Map infoMap, Predicate isExpired, - Function writeLog) { - synchronized (infoMap) { - List expired = new ArrayList<>(); - for (Entry entry : infoMap.entrySet()) { - if (isExpired.test(entry.getValue())) { - expired.add(entry.getKey()); - } - } - for (Long k : expired) { - infoMap.remove(k); - writeLog.apply(k); - } - } - } - public StatisticsCache getStatisticsCache() { return statisticsCache; } @@ -371,6 +333,7 @@ protected AnalysisInfo buildAndAssignJob(AnalyzeTblStmt stmt) throws DdlExceptio boolean isSync = stmt.isSync(); Map analysisTaskInfos = new HashMap<>(); createTaskForEachColumns(jobInfo, analysisTaskInfos, isSync); + constructJob(jobInfo, analysisTaskInfos.values()); if (!jobInfo.partitionOnly && stmt.isAllColumns() && StatisticsUtil.isExternalTable(jobInfo.catalogId, jobInfo.dbId, jobInfo.tblId)) { createTableLevelTaskForExternalTable(jobInfo, analysisTaskInfos, isSync); @@ -446,7 +409,6 @@ private void sendJobId(List analysisInfos, boolean proxy) { */ private Map> validateAndGetPartitions(TableIf table, Set columnNames, Set partitionNames, AnalysisType analysisType) throws DdlException { - long tableId = table.getId(); Map> columnToPartitions = columnNames.stream() .collect(Collectors.toMap( @@ -467,27 +429,6 @@ private Map> validateAndGetPartitions(TableIf table, Set> existColAndPartsForStats = StatisticsRepository - .fetchColAndPartsForStats(tableId); - - if (existColAndPartsForStats.isEmpty()) { - // There is no historical statistical information, no need to do validation - return columnToPartitions; - } - - Set existPartIdsForStats = new HashSet<>(); - existColAndPartsForStats.values().forEach(existPartIdsForStats::addAll); - Set idToPartition = StatisticsUtil.getPartitionIds(table); - // Get an invalid set of partitions (those partitions were deleted) - Set invalidPartIds = existPartIdsForStats.stream() - .filter(id -> !idToPartition.contains(id)).collect(Collectors.toSet()); - - if (!invalidPartIds.isEmpty()) { - // Delete invalid partition statistics to avoid affecting table statistics - StatisticsRepository.dropStatistics(invalidPartIds); - } - if (analysisType == AnalysisType.FUNDAMENTALS) { Map> result = table.findReAnalyzeNeededPartitions(); result.keySet().retainAll(columnNames); @@ -721,11 +662,12 @@ public String getJobProgress(long jobId) { public void syncExecute(Collection tasks) { SyncTaskCollection syncTaskCollection = new SyncTaskCollection(tasks); ConnectContext ctx = ConnectContext.get(); + ThreadPoolExecutor syncExecPool = createThreadPoolForSyncAnalyze(); try { ctxToSyncTask.put(ctx, syncTaskCollection); - ThreadPoolExecutor syncExecPool = createThreadPoolForSyncAnalyze(); syncTaskCollection.execute(syncExecPool); } finally { + syncExecPool.shutdown(); ctxToSyncTask.remove(ctx); } } @@ -738,7 +680,7 @@ private ThreadPoolExecutor createThreadPoolForSyncAnalyze() { new SynchronousQueue(), new ThreadFactoryBuilder().setDaemon(true).setNameFormat("SYNC ANALYZE" + "-%d") .build(), new BlockedPolicy(poolName, - (int) TimeUnit.HOURS.toSeconds(Config.analyze_task_timeout_in_hours))); + StatisticsUtil.getAnalyzeTimeout())); } public void dropStats(DropStatsStmt dropStatsStmt) throws DdlException { @@ -760,6 +702,7 @@ public void dropStats(DropStatsStmt dropStatsStmt) throws DdlException { for (String col : cols) { Env.getCurrentEnv().getStatisticsCache().invalidate(tblId, -1L, col); } + tableStats.updatedTime = 0; } logCreateTableStats(tableStats); StatisticsRepository.dropStatistics(tblId, cols); @@ -1129,4 +1072,17 @@ public ColStatsMeta findColStatsMeta(long tblId, String colName) { } return tableStats.findColumnStatsMeta(colName); } + + public AnalysisJob findJob(long id) { + return idToAnalysisJob.get(id); + } + + public void constructJob(AnalysisInfo jobInfo, Collection tasks) { + AnalysisJob job = new AnalysisJob(jobInfo, tasks); + idToAnalysisJob.put(jobInfo.jobId, job); + } + + public void removeJob(long id) { + idToAnalysisJob.remove(id); + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskExecutor.java index 4b133ce0ebfc68..58bae9fe66b5ca 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskExecutor.java @@ -18,9 +18,9 @@ package org.apache.doris.statistics; import org.apache.doris.catalog.Env; -import org.apache.doris.common.Config; import org.apache.doris.common.ThreadPoolManager; import org.apache.doris.common.ThreadPoolManager.BlockedPolicy; +import org.apache.doris.statistics.util.StatisticsUtil; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -36,7 +36,7 @@ public class AnalysisTaskExecutor extends Thread { private static final Logger LOG = LogManager.getLogger(AnalysisTaskExecutor.class); - private final ThreadPoolExecutor executors; + protected final ThreadPoolExecutor executors; private final BlockingQueue taskQueue = new PriorityBlockingQueue(20, @@ -72,18 +72,22 @@ private void cancelExpiredTask() { private void doCancelExpiredJob() { for (;;) { + tryToCancel(); + } + } + + protected void tryToCancel() { + try { + AnalysisTaskWrapper taskWrapper = taskQueue.take(); try { - AnalysisTaskWrapper taskWrapper = taskQueue.take(); - try { - long timeout = TimeUnit.HOURS.toMillis(Config.analyze_task_timeout_in_hours) - - (System.currentTimeMillis() - taskWrapper.getStartTime()); - taskWrapper.get(timeout < 0 ? 0 : timeout, TimeUnit.MILLISECONDS); - } catch (Exception e) { - taskWrapper.cancel(e.getMessage()); - } - } catch (Throwable throwable) { - LOG.warn(throwable); + long timeout = TimeUnit.SECONDS.toMillis(StatisticsUtil.getAnalyzeTimeout()) + - (System.currentTimeMillis() - taskWrapper.getStartTime()); + taskWrapper.get(timeout < 0 ? 0 : timeout, TimeUnit.MILLISECONDS); + } catch (Exception e) { + taskWrapper.cancel(e.getMessage()); } + } catch (Throwable throwable) { + LOG.warn("cancel analysis task failed", throwable); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskWrapper.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskWrapper.java index 9aa3d85992b32c..ffdd375ee9e36d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskWrapper.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/AnalysisTaskWrapper.java @@ -17,7 +17,6 @@ package org.apache.doris.statistics; -import org.apache.doris.catalog.Env; import org.apache.doris.common.util.TimeUtils; import org.apache.doris.common.util.Util; import org.apache.doris.statistics.AnalysisInfo.ScheduleType; @@ -59,9 +58,8 @@ public void run() { if (task.info.scheduleType.equals(ScheduleType.AUTOMATIC) && !StatisticsUtil.inAnalyzeTime( LocalTime.now(TimeUtils.getTimeZone().toZoneId()))) { // TODO: Do we need a separate AnalysisState here? - Env.getCurrentEnv().getAnalysisManager() - .updateTaskStatus(task.info, AnalysisState.FAILED, "Auto task" - + "doesn't get executed within specified time range", System.currentTimeMillis()); + task.job.taskFailed(task, "Auto task" + + "doesn't get executed within specified time range"); return; } executor.putJob(this); @@ -76,15 +74,7 @@ public void run() { if (!task.killed) { if (except != null) { LOG.warn("Analyze {} failed.", task.toString(), except); - Env.getCurrentEnv().getAnalysisManager() - .updateTaskStatus(task.info, - AnalysisState.FAILED, Util.getRootCauseMessage(except), System.currentTimeMillis()); - } else { - LOG.debug("Analyze {} finished, cost time:{}", task.toString(), - System.currentTimeMillis() - startTime); - Env.getCurrentEnv().getAnalysisManager() - .updateTaskStatus(task.info, - AnalysisState.FINISHED, "", System.currentTimeMillis()); + task.job.taskFailed(task, Util.getRootCauseMessage(except)); } } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java index 4f7d588de735f7..3fcebd6c38b504 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/BaseAnalysisTask.java @@ -22,14 +22,12 @@ import org.apache.doris.catalog.DatabaseIf; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.TableIf; -import org.apache.doris.common.Config; import org.apache.doris.datasource.CatalogIf; -import org.apache.doris.qe.AuditLogHelper; -import org.apache.doris.qe.QueryState; -import org.apache.doris.qe.QueryState.MysqlStateType; +import org.apache.doris.qe.AutoCloseConnectContext; import org.apache.doris.qe.StmtExecutor; import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod; import org.apache.doris.statistics.AnalysisInfo.AnalysisType; +import org.apache.doris.statistics.AnalysisInfo.JobType; import org.apache.doris.statistics.util.DBObjects; import org.apache.doris.statistics.util.StatisticsUtil; @@ -38,6 +36,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.Collections; import java.util.concurrent.TimeUnit; public abstract class BaseAnalysisTask { @@ -52,59 +51,25 @@ public abstract class BaseAnalysisTask { + "else NDV(`${colName}`) * ${scaleFactor} end AS ndv, " ; - /** - * Stats stored in the column_statistics table basically has two types, `part_id` is null which means it is - * aggregate from partition level stats, `part_id` is not null which means it is partition level stats. - * For latter, it's id field contains part id, for previous doesn't. - */ - protected static final String INSERT_PART_STATISTICS = "INSERT INTO " - + "${internalDB}.${columnStatTbl}" - + " SELECT " - + "CONCAT(${tblId}, '-', ${idxId}, '-', '${colId}', '-', ${partId}) AS id, " - + "${catalogId} AS catalog_id, " - + "${dbId} AS db_id, " - + "${tblId} AS tbl_id, " - + "${idxId} AS idx_id, " - + "'${colId}' AS col_id, " - + "${partId} AS part_id, " - + "COUNT(1) AS row_count, " - + "NDV(`${colName}`) AS ndv, " - + "SUM(CASE WHEN `${colName}` IS NULL THEN 1 ELSE 0 END) AS null_count, " - + "MIN(`${colName}`) AS min, " - + "MAX(`${colName}`) AS max, " - + "${dataSizeFunction} AS data_size, " - + "NOW() "; - - protected static final String INSERT_COL_STATISTICS = "INSERT INTO " - + "${internalDB}.${columnStatTbl}" - + " SELECT id, catalog_id, db_id, tbl_id, idx_id, col_id, part_id, row_count, " - + " ndv, null_count," - + " to_base64(CAST(min AS string)), to_base64(CAST(max AS string)), data_size, update_time\n" - + " FROM \n" - + " (SELECT CONCAT(${tblId}, '-', ${idxId}, '-', '${colId}') AS id, " + protected static final String COLLECT_COL_STATISTICS = + "SELECT CONCAT(${tblId}, '-', ${idxId}, '-', '${colId}') AS id, " + " ${catalogId} AS catalog_id, " + " ${dbId} AS db_id, " + " ${tblId} AS tbl_id, " + " ${idxId} AS idx_id, " + " '${colId}' AS col_id, " + " NULL AS part_id, " - + " SUM(count) AS row_count, \n" - + " SUM(null_count) AS null_count, " - + " MIN(CAST(from_base64(min) AS ${type})) AS min, " - + " MAX(CAST(from_base64(max) AS ${type})) AS max, " - + " SUM(data_size_in_bytes) AS data_size, " - + " NOW() AS update_time \n" - + " FROM ${internalDB}.${columnStatTbl}" - + " WHERE ${internalDB}.${columnStatTbl}.db_id = '${dbId}' AND " - + " ${internalDB}.${columnStatTbl}.tbl_id='${tblId}' AND " - + " ${internalDB}.${columnStatTbl}.col_id='${colId}' AND " - + " ${internalDB}.${columnStatTbl}.idx_id='${idxId}' AND " - + " ${internalDB}.${columnStatTbl}.part_id IS NOT NULL" - + " ) t1, \n"; - - protected static final String ANALYZE_PARTITION_COLUMN_TEMPLATE = "INSERT INTO " - + "${internalDB}.${columnStatTbl}" - + " SELECT " + + " COUNT(1) AS row_count, " + + " NDV(`${colName}`) AS ndv, " + + " COUNT(1) - COUNT(${colName}) AS null_count, " + + " CAST(MIN(${colName}) AS STRING) AS min, " + + " CAST(MAX(${colName}) AS STRING) AS max, " + + " ${dataSizeFunction} AS data_size, " + + " NOW() AS update_time " + + " FROM `${dbName}`.`${tblName}`"; + + protected static final String ANALYZE_PARTITION_COLUMN_TEMPLATE = + " SELECT " + "CONCAT(${tblId}, '-', ${idxId}, '-', '${colId}') AS id, " + "${catalogId} AS catalog_id, " + "${dbId} AS db_id, " @@ -115,8 +80,8 @@ public abstract class BaseAnalysisTask { + "${row_count} AS row_count, " + "${ndv} AS ndv, " + "${null_count} AS null_count, " - + "to_base64('${min}') AS min, " - + "to_base64('${max}') AS max, " + + "'${min}' AS min, " + + "'${max}' AS max, " + "${data_size} AS data_size, " + "NOW() "; @@ -136,6 +101,8 @@ public abstract class BaseAnalysisTask { protected TableSample tableSample = null; + protected AnalysisJob job; + @VisibleForTesting public BaseAnalysisTask() { @@ -192,6 +159,7 @@ protected void executeWithRetry() { } LOG.warn("Failed to execute analysis task, retried times: {}", retriedTimes++, t); if (retriedTimes > StatisticConstants.ANALYZE_TASK_RETRY_TIMES) { + job.taskFailed(this, t.getMessage()); throw new RuntimeException(t); } StatisticsUtil.sleep(TimeUnit.SECONDS.toMillis(2 ^ retriedTimes) * 10); @@ -266,11 +234,10 @@ protected TableSample getTableSample() { return new TableSample(true, (long) info.samplePercent); } else if (info.sampleRows > 0) { return new TableSample(false, info.sampleRows); - } else if (info.analysisMethod == AnalysisMethod.FULL - && Config.enable_auto_sample - && tbl.getDataSize(true) > Config.huge_table_lower_bound_size_in_bytes) { + } else if (info.jobType.equals(JobType.SYSTEM) && info.analysisMethod == AnalysisMethod.FULL + && tbl.getDataSize(true) > StatisticsUtil.getHugeTableLowerBoundSizeInBytes()) { // If user doesn't specify sample percent/rows, use auto sample and update sample rows in analysis info. - return new TableSample(false, (long) Config.huge_table_default_sample_rows); + return new TableSample(false, StatisticsUtil.getHugeTableSampleRows()); } else { return null; } @@ -283,23 +250,20 @@ public String toString() { col == null ? "TableRowCount" : col.getName()); } - protected void executeWithExceptionOnFail(StmtExecutor stmtExecutor) throws Exception { - if (killed) { - return; - } - LOG.debug("execute internal sql: {}", stmtExecutor.getOriginStmt()); - try { - stmtExecutor.execute(); - QueryState queryState = stmtExecutor.getContext().getState(); - if (queryState.getStateType().equals(MysqlStateType.ERR)) { - throw new RuntimeException(String.format("Failed to analyze %s.%s.%s, error: %s sql: %s", - catalog.getName(), db.getFullName(), info.colName, stmtExecutor.getOriginStmt().toString(), - queryState.getErrorMessage())); - } + public void setJob(AnalysisJob job) { + this.job = job; + } + + protected void runQuery(String sql) { + long startTime = System.currentTimeMillis(); + try (AutoCloseConnectContext a = StatisticsUtil.buildConnectContext()) { + stmtExecutor = new StmtExecutor(a.connectContext, sql); + stmtExecutor.executeInternalQuery(); + ColStatsData colStatsData = new ColStatsData(stmtExecutor.executeInternalQuery().get(0)); + job.appendBuf(this, Collections.singletonList(colStatsData)); } finally { - AuditLogHelper.logAuditLog(stmtExecutor.getContext(), stmtExecutor.getOriginStmt().toString(), - stmtExecutor.getParsedStmt(), stmtExecutor.getQueryStatisticsForAuditLog(), - true); + LOG.debug("End cost time in secs: " + (System.currentTimeMillis() - startTime) / 1000); } } + } diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/ColStatsData.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/ColStatsData.java index 6c94326a9424ec..41936232afdfed 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/ColStatsData.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/ColStatsData.java @@ -19,6 +19,8 @@ import org.apache.doris.statistics.util.StatisticsUtil; +import com.google.common.annotations.VisibleForTesting; + import java.nio.charset.StandardCharsets; import java.util.Base64; import java.util.StringJoiner; @@ -54,6 +56,18 @@ public class ColStatsData { public final String updateTime; + @VisibleForTesting + public ColStatsData() { + statsId = new StatsId(); + count = 0; + ndv = 0; + nullCount = 0; + minLit = null; + maxLit = null; + dataSizeInBytes = 0; + updateTime = null; + } + public ColStatsData(ResultRow row) { this.statsId = new StatsId(row); this.count = (long) Double.parseDouble(row.get(7)); diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/HMSAnalysisTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/HMSAnalysisTask.java index 4583237f8c61f5..049e80d52fd9a9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/HMSAnalysisTask.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/HMSAnalysisTask.java @@ -23,26 +23,19 @@ import org.apache.doris.common.FeConstants; import org.apache.doris.datasource.hive.HiveMetaStoreCache; import org.apache.doris.external.hive.util.HiveUtil; -import org.apache.doris.qe.AutoCloseConnectContext; -import org.apache.doris.qe.QueryState; -import org.apache.doris.qe.StmtExecutor; import org.apache.doris.statistics.util.StatisticsUtil; -import com.google.common.collect.Lists; import com.google.common.collect.Sets; import org.apache.commons.text.StringSubstitutor; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import java.util.ArrayList; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Random; import java.util.Set; -import java.util.StringJoiner; import java.util.stream.Collectors; public class HMSAnalysisTask extends BaseAnalysisTask { @@ -51,9 +44,7 @@ public class HMSAnalysisTask extends BaseAnalysisTask { // While doing sample analysis, the sampled ndv result will multiply a factor (total size/sample size) // if ndv(col)/count(col) is greater than this threshold. - private static final String ANALYZE_TABLE_TEMPLATE = "INSERT INTO " - + "${internalDB}.${columnStatTbl}" - + " SELECT " + private static final String ANALYZE_TABLE_TEMPLATE = " SELECT " + "CONCAT(${tblId}, '-', ${idxId}, '-', '${colId}') AS id, " + "${catalogId} AS catalog_id, " + "${dbId} AS db_id, " @@ -70,28 +61,9 @@ public class HMSAnalysisTask extends BaseAnalysisTask { + "NOW() " + "FROM `${catalogName}`.`${dbName}`.`${tblName}` ${sampleExpr}"; - private static final String ANALYZE_PARTITION_TEMPLATE = " SELECT " - + "CONCAT(${tblId}, '-', ${idxId}, '-', '${colId}', '-', ${partId}) AS id, " - + "${catalogId} AS catalog_id, " - + "${dbId} AS db_id, " - + "${tblId} AS tbl_id, " - + "${idxId} AS idx_id, " - + "'${colId}' AS col_id, " - + "${partId} AS part_id, " - + "COUNT(1) AS row_count, " - + "NDV(`${colName}`) AS ndv, " - + "SUM(CASE WHEN `${colName}` IS NULL THEN 1 ELSE 0 END) AS null_count, " - + "to_base64(MIN(`${colName}`)) AS min, " - + "to_base64(MAX(`${colName}`)) AS max, " - + "${dataSizeFunction} AS data_size, " - + "NOW() FROM `${catalogName}`.`${dbName}`.`${tblName}` where "; - private static final String ANALYZE_TABLE_COUNT_TEMPLATE = "SELECT ROUND(COUNT(1) * ${scaleFactor}) as rowCount " + "FROM `${catalogName}`.`${dbName}`.`${tblName}` ${sampleExpr}"; - // cache stats for each partition, it would be inserted into column_statistics in a batch. - private final List> buf = new ArrayList<>(); - private final boolean isTableLevelTask; private final boolean isPartitionOnly; private Set partitionNames; @@ -131,25 +103,16 @@ private void getTableStats() throws Exception { * Get column statistics and insert the result to __internal_schema.column_statistics */ private void getTableColumnStats() throws Exception { - if (isPartitionOnly) { - getPartitionNames(); - List partitionAnalysisSQLs = new ArrayList<>(); - for (String partId : this.partitionNames) { - partitionAnalysisSQLs.add(generateSqlForPartition(partId)); - } - execSQLs(partitionAnalysisSQLs); - } else { - if (!info.usingSqlForPartitionColumn && isPartitionColumn()) { - try { - getPartitionColumnStats(); - } catch (Exception e) { - LOG.warn("Failed to collect stats for partition col {} using metadata, " - + "fallback to normal collection", col.getName(), e); - getOrdinaryColumnStats(); - } - } else { + if (!info.usingSqlForPartitionColumn && isPartitionColumn()) { + try { + getPartitionColumnStats(); + } catch (Exception e) { + LOG.warn("Failed to collect stats for partition col {} using metadata, " + + "fallback to normal collection", col.getName(), e); getOrdinaryColumnStats(); } + } else { + getOrdinaryColumnStats(); } } @@ -182,7 +145,7 @@ private void getOrdinaryColumnStats() throws Exception { params.put("maxFunction", getMaxFunction()); StringSubstitutor stringSubstitutor = new StringSubstitutor(params); String sql = stringSubstitutor.replace(sb.toString()); - executeInsertSql(sql); + runQuery(sql); } private void getPartitionColumnStats() throws Exception { @@ -227,7 +190,7 @@ private void getPartitionColumnStats() throws Exception { params.put("data_size", String.valueOf(dataSize)); StringSubstitutor stringSubstitutor = new StringSubstitutor(params); String sql = stringSubstitutor.replace(ANALYZE_PARTITION_COLUMN_TEMPLATE); - executeInsertSql(sql); + runQuery(sql); } private String updateMinValue(String currentMin, String value) { @@ -278,7 +241,7 @@ private void getPartitionNames() { partitionNames = table.getPartitionNames(); } else if (info.partitionCount > 0) { partitionNames = table.getPartitionNames().stream() - .limit(info.partitionCount).collect(Collectors.toSet()); + .limit(info.partitionCount).collect(Collectors.toSet()); } if (partitionNames == null || partitionNames.isEmpty()) { throw new RuntimeException("Not a partition table or no partition specified."); @@ -286,80 +249,6 @@ private void getPartitionNames() { } } - private String generateSqlForPartition(String partId) { - StringBuilder sb = new StringBuilder(); - sb.append(ANALYZE_PARTITION_TEMPLATE); - String[] splits = partId.split("/"); - for (int i = 0; i < splits.length; i++) { - String[] kv = splits[i].split("="); - sb.append(kv[0]); - sb.append("='"); - sb.append(kv[1]); - sb.append("'"); - if (i < splits.length - 1) { - sb.append(" and "); - } - } - Map params = buildStatsParams(partId); - params.put("dataSizeFunction", getDataSizeFunction(col)); - return new StringSubstitutor(params).replace(sb.toString()); - } - - public void execSQLs(List partitionAnalysisSQLs) throws Exception { - long startTime = System.currentTimeMillis(); - LOG.debug("analyze task {} start at {}", info.toString(), new Date()); - try (AutoCloseConnectContext r = StatisticsUtil.buildConnectContext()) { - List> sqlGroups = Lists.partition(partitionAnalysisSQLs, StatisticConstants.UNION_ALL_LIMIT); - for (List group : sqlGroups) { - if (killed) { - return; - } - StringJoiner partitionCollectSQL = new StringJoiner("UNION ALL"); - group.forEach(partitionCollectSQL::add); - stmtExecutor = new StmtExecutor(r.connectContext, partitionCollectSQL.toString()); - buf.add(stmtExecutor.executeInternalQuery() - .stream().map(ColStatsData::new).collect(Collectors.toList())); - QueryState queryState = r.connectContext.getState(); - if (queryState.getStateType().equals(QueryState.MysqlStateType.ERR)) { - throw new RuntimeException(String.format("Failed to analyze %s.%s.%s, error: %s sql: %s", - catalog.getName(), db.getFullName(), info.colName, partitionCollectSQL, - queryState.getErrorMessage())); - } - } - for (List colStatsDataList : buf) { - StringBuilder batchInsertSQL = - new StringBuilder("INSERT INTO " + StatisticConstants.FULL_QUALIFIED_STATS_TBL_NAME - + " VALUES "); - StringJoiner sj = new StringJoiner(","); - colStatsDataList.forEach(c -> sj.add(c.toSQL(true))); - batchInsertSQL.append(sj); - stmtExecutor = new StmtExecutor(r.connectContext, batchInsertSQL.toString()); - executeWithExceptionOnFail(stmtExecutor); - } - } finally { - LOG.debug("analyze task {} end. cost {}ms", info, System.currentTimeMillis() - startTime); - } - - } - - private void executeInsertSql(String sql) throws Exception { - long startTime = System.currentTimeMillis(); - try (AutoCloseConnectContext r = StatisticsUtil.buildConnectContext()) { - r.connectContext.getSessionVariable().disableNereidsPlannerOnce(); - this.stmtExecutor = new StmtExecutor(r.connectContext, sql); - r.connectContext.setExecutor(stmtExecutor); - this.stmtExecutor.execute(); - QueryState queryState = r.connectContext.getState(); - if (queryState.getStateType().equals(QueryState.MysqlStateType.ERR)) { - LOG.warn(String.format("Failed to analyze %s.%s.%s, sql: [%s], error: [%s]", - catalog.getName(), db.getFullName(), info.colName, sql, queryState.getErrorMessage())); - throw new RuntimeException(queryState.getErrorMessage()); - } - LOG.debug(String.format("Analyze %s.%s.%s done. SQL: [%s]. Cost %d ms.", - catalog.getName(), db.getFullName(), info.colName, sql, (System.currentTimeMillis() - startTime))); - } - } - private Map buildStatsParams(String partId) { Map commonParams = new HashMap<>(); String id = StatisticsUtil.constructId(tbl.getId(), -1); diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/JdbcAnalysisTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/JdbcAnalysisTask.java index 5ae66d292dc43d..649b075c673f5d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/JdbcAnalysisTask.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/JdbcAnalysisTask.java @@ -20,25 +20,17 @@ import org.apache.doris.catalog.Env; import org.apache.doris.catalog.external.JdbcExternalTable; import org.apache.doris.common.FeConstants; -import org.apache.doris.qe.AutoCloseConnectContext; -import org.apache.doris.qe.QueryState; -import org.apache.doris.qe.StmtExecutor; import org.apache.doris.statistics.util.StatisticsUtil; import org.apache.commons.text.StringSubstitutor; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; import java.util.HashMap; import java.util.List; import java.util.Map; public class JdbcAnalysisTask extends BaseAnalysisTask { - private static final Logger LOG = LogManager.getLogger(JdbcAnalysisTask.class); - private static final String ANALYZE_SQL_TABLE_TEMPLATE = "INSERT INTO " - + "${internalDB}.${columnStatTbl}" - + " SELECT " + private static final String ANALYZE_SQL_TABLE_TEMPLATE = " SELECT " + "CONCAT(${tblId}, '-', ${idxId}, '-', '${colId}') AS id, " + "${catalogId} AS catalog_id, " + "${dbId} AS db_id, " @@ -49,8 +41,8 @@ public class JdbcAnalysisTask extends BaseAnalysisTask { + "COUNT(1) AS row_count, " + "NDV(`${colName}`) AS ndv, " + "SUM(CASE WHEN `${colName}` IS NULL THEN 1 ELSE 0 END) AS null_count, " - + "to_base64(MIN(`${colName}`)) AS min, " - + "to_base64(MAX(`${colName}`)) AS max, " + + "MIN(`${colName}`) AS min, " + + "MAX(`${colName}`) AS max, " + "${dataSizeFunction} AS data_size, " + "NOW() " + "FROM `${catalogName}`.`${dbName}`.`${tblName}`"; @@ -117,25 +109,7 @@ private void getTableColumnStats() throws Exception { params.put("dataSizeFunction", getDataSizeFunction(col)); StringSubstitutor stringSubstitutor = new StringSubstitutor(params); String sql = stringSubstitutor.replace(sb.toString()); - executeInsertSql(sql); - } - - private void executeInsertSql(String sql) throws Exception { - long startTime = System.currentTimeMillis(); - try (AutoCloseConnectContext r = StatisticsUtil.buildConnectContext()) { - r.connectContext.getSessionVariable().disableNereidsPlannerOnce(); - this.stmtExecutor = new StmtExecutor(r.connectContext, sql); - r.connectContext.setExecutor(stmtExecutor); - this.stmtExecutor.execute(); - QueryState queryState = r.connectContext.getState(); - if (queryState.getStateType().equals(QueryState.MysqlStateType.ERR)) { - LOG.warn(String.format("Failed to analyze %s.%s.%s, sql: [%s], error: [%s]", - catalog.getName(), db.getFullName(), info.colName, sql, queryState.getErrorMessage())); - throw new RuntimeException(queryState.getErrorMessage()); - } - LOG.debug(String.format("Analyze %s.%s.%s done. SQL: [%s]. Cost %d ms.", - catalog.getName(), db.getFullName(), info.colName, sql, (System.currentTimeMillis() - startTime))); - } + runQuery(sql); } private Map buildTableStatsParams(String partId) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/MVAnalysisTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/MVAnalysisTask.java deleted file mode 100644 index 6a43c5092fa072..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/MVAnalysisTask.java +++ /dev/null @@ -1,152 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package org.apache.doris.statistics; - -import org.apache.doris.analysis.CreateMaterializedViewStmt; -import org.apache.doris.analysis.Expr; -import org.apache.doris.analysis.FunctionCallExpr; -import org.apache.doris.analysis.PartitionNames; -import org.apache.doris.analysis.SelectListItem; -import org.apache.doris.analysis.SelectStmt; -import org.apache.doris.analysis.SlotRef; -import org.apache.doris.analysis.SqlParser; -import org.apache.doris.analysis.SqlScanner; -import org.apache.doris.analysis.TableRef; -import org.apache.doris.catalog.Column; -import org.apache.doris.catalog.Env; -import org.apache.doris.catalog.MaterializedIndexMeta; -import org.apache.doris.catalog.OlapTable; -import org.apache.doris.common.FeConstants; -import org.apache.doris.common.util.SqlParserUtils; -import org.apache.doris.statistics.util.StatisticsUtil; - -import com.google.common.base.Preconditions; - -import java.io.StringReader; -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -/** - * Analysis for the materialized view, only gets constructed when the AnalyzeStmt is not set which - * columns to be analyzed. - * TODO: Supports multi-table mv - */ -public class MVAnalysisTask extends BaseAnalysisTask { - - private static final String ANALYZE_MV_PART = INSERT_PART_STATISTICS - + " FROM (${sql}) mv ${sampleExpr}"; - - private static final String ANALYZE_MV_COL = INSERT_COL_STATISTICS - + " (SELECT NDV(`${colName}`) AS ndv " - + " FROM (${sql}) mv) t2"; - - private MaterializedIndexMeta meta; - - private SelectStmt selectStmt; - - private OlapTable olapTable; - - public MVAnalysisTask(AnalysisInfo info) { - super(info); - init(); - } - - private void init() { - olapTable = (OlapTable) tbl; - meta = olapTable.getIndexMetaByIndexId(info.indexId); - Preconditions.checkState(meta != null); - String mvDef = meta.getDefineStmt().originStmt; - SqlScanner input = - new SqlScanner(new StringReader(mvDef), 0L); - SqlParser parser = new SqlParser(input); - CreateMaterializedViewStmt cmv = null; - try { - cmv = (CreateMaterializedViewStmt) SqlParserUtils.getStmt(parser, 0); - } catch (Exception e) { - throw new RuntimeException(e); - } - selectStmt = cmv.getSelectStmt(); - selectStmt.getTableRefs().get(0).getName().setDb(db.getFullName()); - } - - @Override - public void doExecute() throws Exception { - for (Column column : meta.getSchema()) { - SelectStmt selectOne = (SelectStmt) selectStmt.clone(); - TableRef tableRef = selectOne.getTableRefs().get(0); - SelectListItem selectItem = selectOne.getSelectList().getItems() - .stream() - .filter(i -> isCorrespondingToColumn(i, column)) - .findFirst() - .get(); - selectItem.setAlias(column.getName()); - Map params = new HashMap<>(); - for (String partName : tbl.getPartitionNames()) { - PartitionNames partitionName = new PartitionNames(false, - Collections.singletonList(partName)); - tableRef.setPartitionNames(partitionName); - String sql = selectOne.toSql(); - params.put("internalDB", FeConstants.INTERNAL_DB_NAME); - params.put("columnStatTbl", StatisticConstants.STATISTIC_TBL_NAME); - params.put("catalogId", String.valueOf(catalog.getId())); - params.put("dbId", String.valueOf(db.getId())); - params.put("tblId", String.valueOf(tbl.getId())); - params.put("idxId", String.valueOf(meta.getIndexId())); - String colName = column.getName(); - params.put("colId", colName); - String partId = olapTable.getPartition(partName) == null ? "NULL" : - String.valueOf(olapTable.getPartition(partName).getId()); - params.put("partId", partId); - params.put("dataSizeFunction", getDataSizeFunction(column)); - params.put("dbName", db.getFullName()); - params.put("colName", colName); - params.put("tblName", tbl.getName()); - params.put("sql", sql); - StatisticsUtil.execUpdate(ANALYZE_MV_PART, params); - } - params.remove("partId"); - params.remove("sampleExpr"); - params.put("type", column.getType().toString()); - StatisticsUtil.execUpdate(ANALYZE_MV_COL, params); - Env.getCurrentEnv().getStatisticsCache() - .refreshColStatsSync(meta.getIndexId(), meta.getIndexId(), column.getName()); - } - } - - // Based on the fact that materialized view create statement's select expr only contains basic SlotRef and - // AggregateFunction. - private boolean isCorrespondingToColumn(SelectListItem item, Column column) { - Expr expr = item.getExpr(); - if (expr instanceof SlotRef) { - SlotRef slotRef = (SlotRef) expr; - return slotRef.getColumnName().equalsIgnoreCase(column.getName()); - } - if (expr instanceof FunctionCallExpr) { - FunctionCallExpr func = (FunctionCallExpr) expr; - SlotRef slotRef = (SlotRef) func.getChild(0); - return slotRef.getColumnName().equalsIgnoreCase(column.getName()); - } - return false; - } - - @Override - protected void afterExecution() { - // DO NOTHING - } -} diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java index 185a582cde436e..b0c4b0b6c0e5c8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/OlapAnalysisTask.java @@ -22,28 +22,21 @@ import org.apache.doris.catalog.Partition; import org.apache.doris.common.FeConstants; import org.apache.doris.common.Pair; -import org.apache.doris.datasource.InternalCatalog; import org.apache.doris.qe.AutoCloseConnectContext; -import org.apache.doris.qe.QueryState; -import org.apache.doris.qe.QueryState.MysqlStateType; import org.apache.doris.qe.StmtExecutor; import org.apache.doris.statistics.AnalysisInfo.JobType; import org.apache.doris.statistics.util.StatisticsUtil; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.Lists; import org.apache.commons.text.StringSubstitutor; import java.security.SecureRandom; import java.util.ArrayList; -import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.StringJoiner; import java.util.stream.Collectors; /** @@ -51,29 +44,6 @@ */ public class OlapAnalysisTask extends BaseAnalysisTask { - // TODO Currently, NDV is computed for the full table; in fact, - // NDV should only be computed for the relevant partition. - private static final String ANALYZE_COLUMN_SQL_TEMPLATE = INSERT_COL_STATISTICS - + " (SELECT NDV(`${colName}`) AS ndv " - + " FROM `${dbName}`.`${tblName}`) t2"; - - private static final String COLLECT_PARTITION_STATS_SQL_TEMPLATE = - " SELECT " - + "CONCAT(${tblId}, '-', ${idxId}, '-', '${colId}', '-', ${partId}) AS id, " - + "${catalogId} AS catalog_id, " - + "${dbId} AS db_id, " - + "${tblId} AS tbl_id, " - + "${idxId} AS idx_id, " - + "'${colId}' AS col_id, " - + "${partId} AS part_id, " - + "COUNT(1) AS row_count, " - + "NDV(`${colName}`) AS ndv, " - + "SUM(CASE WHEN `${colName}` IS NULL THEN 1 ELSE 0 END) AS null_count, " - + "MIN(`${colName}`) AS min, " - + "MAX(`${colName}`) AS max, " - + "${dataSizeFunction} AS data_size, " - + "NOW() FROM `${dbName}`.`${tblName}` PARTITION ${partitionName}"; - private static final String SAMPLE_COLUMN_SQL_TEMPLATE = "SELECT " + "CONCAT(${tblId}, '-', ${idxId}, '-', '${colId}') AS id, " + "${catalogId} AS catalog_id, " @@ -92,9 +62,6 @@ public class OlapAnalysisTask extends BaseAnalysisTask { + "FROM `${dbName}`.`${tblName}`" + "${tablets}"; - // cache stats for each partition, it would be inserted into column_statistics in a batch. - private final List> buf = new ArrayList<>(); - @VisibleForTesting public OlapAnalysisTask() { } @@ -148,45 +115,7 @@ protected void doSample() throws Exception { stmtExecutor = new StmtExecutor(r.connectContext, stringSubstitutor.replace(SAMPLE_COLUMN_SQL_TEMPLATE)); // Scalar query only return one row ColStatsData colStatsData = new ColStatsData(stmtExecutor.executeInternalQuery().get(0)); - OlapTable olapTable = (OlapTable) tbl; - Collection partitions = olapTable.getPartitions(); - int partitionCount = partitions.size(); - List values = partitions.stream().map(p -> String.format( - "(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())", - StatisticsUtil.quote(StatisticsUtil.constructId(tbl.getId(), -1, col.getName(), p.getId())), - InternalCatalog.INTERNAL_CATALOG_ID, - db.getId(), - tbl.getId(), - -1, - StatisticsUtil.quote(col.getName()), - p.getId(), - colStatsData.count / partitionCount, - colStatsData.ndv / partitionCount, - colStatsData.nullCount / partitionCount, - StatisticsUtil.quote(colStatsData.minLit), - StatisticsUtil.quote(colStatsData.maxLit), - colStatsData.dataSizeInBytes / partitionCount)).collect(Collectors.toList()); - values.add(String.format( - "(%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, NOW())", - StatisticsUtil.quote(StatisticsUtil.constructId(tbl.getId(), -1, col.getName())), - InternalCatalog.INTERNAL_CATALOG_ID, - db.getId(), - tbl.getId(), - -1, - StatisticsUtil.quote(col.getName()), - "NULL", - colStatsData.count, - colStatsData.ndv, - colStatsData.nullCount, - StatisticsUtil.quote(colStatsData.minLit), - StatisticsUtil.quote(colStatsData.maxLit), - colStatsData.dataSizeInBytes)); - String insertSQL = "INSERT INTO " - + StatisticConstants.FULL_QUALIFIED_STATS_TBL_NAME - + " VALUES " - + String.join(",", values); - stmtExecutor = new StmtExecutor(r.connectContext, insertSQL); - executeWithExceptionOnFail(stmtExecutor); + job.appendBuf(this, Collections.singletonList(colStatsData)); } } @@ -198,6 +127,7 @@ protected void doSample() throws Exception { protected void doFull() throws Exception { Set partitionNames = info.colToPartitions.get(info.colName); if (partitionNames.isEmpty()) { + job.appendBuf(this, Collections.emptyList()); return; } Map params = new HashMap<>(); @@ -212,68 +142,14 @@ protected void doFull() throws Exception { params.put("dbName", db.getFullName()); params.put("colName", String.valueOf(info.colName)); params.put("tblName", String.valueOf(tbl.getName())); - List partitionAnalysisSQLs = new ArrayList<>(); - try { - tbl.readLock(); - - for (String partitionName : partitionNames) { - Partition part = tbl.getPartition(partitionName); - if (part == null) { - continue; - } - params.put("partId", String.valueOf(tbl.getPartition(partitionName).getId())); - // Avoid error when get the default partition - params.put("partitionName", "`" + partitionName + "`"); - StringSubstitutor stringSubstitutor = new StringSubstitutor(params); - partitionAnalysisSQLs.add(stringSubstitutor.replace(COLLECT_PARTITION_STATS_SQL_TEMPLATE)); - } - } finally { - tbl.readUnlock(); - } - execSQLs(partitionAnalysisSQLs, params); + execSQL(params); } @VisibleForTesting - public void execSQLs(List partitionAnalysisSQLs, Map params) throws Exception { - long startTime = System.currentTimeMillis(); - LOG.debug("analyze task {} start at {}", info.toString(), new Date()); - try (AutoCloseConnectContext r = StatisticsUtil.buildConnectContext(info.jobType.equals(JobType.SYSTEM))) { - List> sqlGroups = Lists.partition(partitionAnalysisSQLs, StatisticConstants.UNION_ALL_LIMIT); - for (List group : sqlGroups) { - if (killed) { - return; - } - StringJoiner partitionCollectSQL = new StringJoiner("UNION ALL"); - group.forEach(partitionCollectSQL::add); - stmtExecutor = new StmtExecutor(r.connectContext, partitionCollectSQL.toString()); - buf.add(stmtExecutor.executeInternalQuery() - .stream().map(ColStatsData::new).collect(Collectors.toList())); - QueryState queryState = r.connectContext.getState(); - if (queryState.getStateType().equals(MysqlStateType.ERR)) { - throw new RuntimeException(String.format("Failed to analyze %s.%s.%s, error: %s sql: %s", - catalog.getName(), db.getFullName(), info.colName, partitionCollectSQL, - queryState.getErrorMessage())); - } - } - for (List colStatsDataList : buf) { - StringBuilder batchInsertSQL = - new StringBuilder("INSERT INTO " + StatisticConstants.FULL_QUALIFIED_STATS_TBL_NAME - + " VALUES "); - StringJoiner sj = new StringJoiner(","); - colStatsDataList.forEach(c -> sj.add(c.toSQL(true))); - batchInsertSQL.append(sj.toString()); - stmtExecutor = new StmtExecutor(r.connectContext, batchInsertSQL.toString()); - executeWithExceptionOnFail(stmtExecutor); - } - params.put("type", col.getType().toString()); - StringSubstitutor stringSubstitutor = new StringSubstitutor(params); - String sql = stringSubstitutor.replace(ANALYZE_COLUMN_SQL_TEMPLATE); - stmtExecutor = new StmtExecutor(r.connectContext, sql); - executeWithExceptionOnFail(stmtExecutor); - } finally { - LOG.debug("analyze task {} end. cost {}ms", info, - System.currentTimeMillis() - startTime); - } + public void execSQL(Map params) throws Exception { + StringSubstitutor stringSubstitutor = new StringSubstitutor(params); + String collectColStats = stringSubstitutor.replace(COLLECT_COL_STATISTICS); + runQuery(collectColStats); } // Get sample tablets id and scale up scaleFactor diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticConstants.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticConstants.java index e6b8297d0c0b01..f008c8fe3015ff 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticConstants.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticConstants.java @@ -78,12 +78,20 @@ public class StatisticConstants { public static final int LOAD_RETRY_TIMES = 3; - // union more relation than 512 may cause StackOverFlowException in the future. - public static final int UNION_ALL_LIMIT = 512; - public static final String FULL_AUTO_ANALYZE_START_TIME = "00:00:00"; public static final String FULL_AUTO_ANALYZE_END_TIME = "23:59:59"; + public static final int INSERT_MERGE_ITEM_COUNT = 200; + + public static final long HUGE_TABLE_DEFAULT_SAMPLE_ROWS = 4194304; + public static final long HUGE_TABLE_LOWER_BOUND_SIZE_IN_BYTES = 5L * 1024 * 1024 * 1024; + + public static final long HUGE_TABLE_AUTO_ANALYZE_INTERVAL_IN_MILLIS = TimeUnit.HOURS.toMillis(12); + + public static final int TABLE_STATS_HEALTH_THRESHOLD = 60; + + public static final int ANALYZE_TIMEOUT_IN_SEC = 43200; + static { SYSTEM_DBS.add(SystemInfoService.DEFAULT_CLUSTER + ClusterNamespace.CLUSTER_DELIMITER + FeConstants.INTERNAL_DB_NAME); diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoCollector.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoCollector.java index 8f5bb605b68914..7031aa1956a51a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoCollector.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsAutoCollector.java @@ -113,7 +113,7 @@ protected boolean skip(TableIf table) { if (!(table instanceof OlapTable || table instanceof ExternalTable)) { return true; } - if (table.getDataSize(true) < Config.huge_table_lower_bound_size_in_bytes) { + if (table.getDataSize(true) < StatisticsUtil.getHugeTableLowerBoundSizeInBytes() * 5) { return false; } TableStatsMeta tableStats = Env.getCurrentEnv().getAnalysisManager().findTableStatsStatus(table.getId()); @@ -121,12 +121,13 @@ protected boolean skip(TableIf table) { if (tableStats == null) { return false; } - return System.currentTimeMillis() - tableStats.updatedTime < Config.huge_table_auto_analyze_interval_in_millis; + return System.currentTimeMillis() + - tableStats.updatedTime < StatisticsUtil.getHugeTableAutoAnalyzeIntervalInMillis(); } protected void createAnalyzeJobForTbl(DatabaseIf db, List analysisInfos, TableIf table) { - AnalysisMethod analysisMethod = table.getDataSize(true) > Config.huge_table_lower_bound_size_in_bytes + AnalysisMethod analysisMethod = table.getDataSize(true) > StatisticsUtil.getHugeTableLowerBoundSizeInBytes() ? AnalysisMethod.SAMPLE : AnalysisMethod.FULL; AnalysisInfo jobInfo = new AnalysisInfoBuilder() .setJobId(Env.getCurrentEnv().getNextId()) @@ -141,7 +142,7 @@ protected void createAnalyzeJobForTbl(DatabaseIf db, .setAnalysisType(AnalysisInfo.AnalysisType.FUNDAMENTALS) .setAnalysisMode(AnalysisInfo.AnalysisMode.INCREMENTAL) .setAnalysisMethod(analysisMethod) - .setSampleRows(Config.huge_table_default_sample_rows) + .setSampleRows(StatisticsUtil.getHugeTableSampleRows()) .setScheduleType(ScheduleType.AUTOMATIC) .setState(AnalysisState.PENDING) .setTaskIds(new ArrayList<>()) diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCollector.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCollector.java index c2f1db6bc4a64c..638db553987611 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCollector.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsCollector.java @@ -73,14 +73,15 @@ protected void createSystemAnalysisJob(AnalysisInfo jobInfo) return; } - Map analysisTaskInfos = new HashMap<>(); + Map analysisTasks = new HashMap<>(); AnalysisManager analysisManager = Env.getCurrentEnv().getAnalysisManager(); - analysisManager.createTaskForEachColumns(jobInfo, analysisTaskInfos, false); + analysisManager.createTaskForEachColumns(jobInfo, analysisTasks, false); + Env.getCurrentEnv().getAnalysisManager().constructJob(jobInfo, analysisTasks.values()); if (StatisticsUtil.isExternalTable(jobInfo.catalogId, jobInfo.dbId, jobInfo.tblId)) { - analysisManager.createTableLevelTaskForExternalTable(jobInfo, analysisTaskInfos, false); + analysisManager.createTableLevelTaskForExternalTable(jobInfo, analysisTasks, false); } - Env.getCurrentEnv().getAnalysisManager().registerSysJob(jobInfo, analysisTaskInfos); - analysisTaskInfos.values().forEach(analysisTaskExecutor::submitTask); + Env.getCurrentEnv().getAnalysisManager().registerSysJob(jobInfo, analysisTasks); + analysisTasks.values().forEach(analysisTaskExecutor::submitTask); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsPeriodCollector.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsPeriodCollector.java deleted file mode 100644 index f34ad0f1221de7..00000000000000 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatisticsPeriodCollector.java +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -package org.apache.doris.statistics; - -import org.apache.doris.catalog.Env; -import org.apache.doris.common.Config; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import java.util.List; -import java.util.concurrent.TimeUnit; - -public class StatisticsPeriodCollector extends StatisticsCollector { - private static final Logger LOG = LogManager.getLogger(StatisticsPeriodCollector.class); - - public StatisticsPeriodCollector() { - super("Automatic Analyzer", - TimeUnit.MINUTES.toMillis(Config.auto_check_statistics_in_minutes) / 2, - new AnalysisTaskExecutor(Config.period_analyze_simultaneously_running_task_num)); - } - - @Override - protected void collect() { - try { - AnalysisManager analysisManager = Env.getCurrentEnv().getAnalysisManager(); - List jobInfos = analysisManager.findPeriodicJobs(); - for (AnalysisInfo jobInfo : jobInfos) { - createSystemAnalysisJob(jobInfo); - } - } catch (Exception e) { - LOG.warn("Failed to periodically analyze the statistics." + e); - } - } -} diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatsId.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatsId.java index 3f9b2641b75224..7cd8817a1a487b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/StatsId.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/StatsId.java @@ -19,6 +19,8 @@ import org.apache.doris.statistics.util.StatisticsUtil; +import com.google.common.annotations.VisibleForTesting; + import java.util.StringJoiner; public class StatsId { @@ -34,6 +36,17 @@ public class StatsId { // nullable public final String partId; + @VisibleForTesting + public StatsId() { + this.id = null; + this.catalogId = -1; + this.dbId = -1; + this.tblId = -1; + this.idxId = -1; + this.colId = null; + this.partId = null; + } + public StatsId(ResultRow row) { this.id = row.get(0); this.catalogId = Long.parseLong(row.get(1)); @@ -52,7 +65,7 @@ public String toSQL() { sj.add(String.valueOf(tblId)); sj.add(String.valueOf(idxId)); sj.add(StatisticsUtil.quote(colId)); - sj.add(StatisticsUtil.quote(partId)); + sj.add(partId); return sj.toString(); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java index 169ac3e33838b3..d7bfd826557e34 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java @@ -177,12 +177,14 @@ public static AutoCloseConnectContext buildConnectContext(boolean limitScan) { sessionVariable.enablePageCache = false; sessionVariable.parallelExecInstanceNum = Config.statistics_sql_parallel_exec_instance_num; sessionVariable.parallelPipelineTaskNum = Config.statistics_sql_parallel_exec_instance_num; - sessionVariable.setEnableNereidsPlanner(false); + sessionVariable.setEnableNereidsPlanner(true); + sessionVariable.setEnablePipelineEngine(false); sessionVariable.enableProfile = false; sessionVariable.enableScanRunSerial = limitScan; - sessionVariable.queryTimeoutS = Config.analyze_task_timeout_in_hours * 60 * 60; - sessionVariable.insertTimeoutS = Config.analyze_task_timeout_in_hours * 60 * 60; + sessionVariable.queryTimeoutS = StatisticsUtil.getAnalyzeTimeout(); + sessionVariable.insertTimeoutS = StatisticsUtil.getAnalyzeTimeout(); sessionVariable.enableFileCache = false; + sessionVariable.forbidUnknownColStats = false; connectContext.setEnv(Env.getCurrentEnv()); connectContext.setDatabase(FeConstants.INTERNAL_DB_NAME); connectContext.setQualifiedUser(UserIdentity.ROOT.getQualifiedUser()); @@ -808,7 +810,7 @@ public static boolean isExternalTable(long catalogId, long dbId, long tblId) { public static boolean inAnalyzeTime(LocalTime now) { try { - Pair range = findRangeFromGlobalSessionVar(); + Pair range = findConfigFromGlobalSessionVar(); if (range == null) { return false; } @@ -825,16 +827,16 @@ public static boolean inAnalyzeTime(LocalTime now) { } } - private static Pair findRangeFromGlobalSessionVar() { + private static Pair findConfigFromGlobalSessionVar() { try { String startTime = - findRangeFromGlobalSessionVar(SessionVariable.FULL_AUTO_ANALYZE_START_TIME) + findConfigFromGlobalSessionVar(SessionVariable.FULL_AUTO_ANALYZE_START_TIME) .fullAutoAnalyzeStartTime; // For compatibility if (StringUtils.isEmpty(startTime)) { startTime = StatisticConstants.FULL_AUTO_ANALYZE_START_TIME; } - String endTime = findRangeFromGlobalSessionVar(SessionVariable.FULL_AUTO_ANALYZE_END_TIME) + String endTime = findConfigFromGlobalSessionVar(SessionVariable.FULL_AUTO_ANALYZE_END_TIME) .fullAutoAnalyzeEndTime; if (StringUtils.isEmpty(startTime)) { endTime = StatisticConstants.FULL_AUTO_ANALYZE_END_TIME; @@ -846,7 +848,7 @@ private static Pair findRangeFromGlobalSessionVar() { } } - private static SessionVariable findRangeFromGlobalSessionVar(String varName) throws Exception { + protected static SessionVariable findConfigFromGlobalSessionVar(String varName) throws Exception { SessionVariable sessionVariable = VariableMgr.newSessionVariable(); VariableExpr variableExpr = new VariableExpr(varName, SetType.GLOBAL); VariableMgr.getValue(sessionVariable, variableExpr); @@ -855,10 +857,71 @@ private static SessionVariable findRangeFromGlobalSessionVar(String varName) thr public static boolean enableAutoAnalyze() { try { - return findRangeFromGlobalSessionVar(SessionVariable.ENABLE_FULL_AUTO_ANALYZE).enableFullAutoAnalyze; + return findConfigFromGlobalSessionVar(SessionVariable.ENABLE_FULL_AUTO_ANALYZE).enableFullAutoAnalyze; } catch (Exception e) { LOG.warn("Fail to get value of enable auto analyze, return false by default", e); } return false; } + + public static int getInsertMergeCount() { + try { + return findConfigFromGlobalSessionVar(SessionVariable.STATS_INSERT_MERGE_ITEM_COUNT) + .statsInsertMergeItemCount; + } catch (Exception e) { + LOG.warn("Failed to get value of insert_merge_item_count, return default", e); + } + return StatisticConstants.INSERT_MERGE_ITEM_COUNT; + } + + public static long getHugeTableSampleRows() { + try { + return findConfigFromGlobalSessionVar(SessionVariable.HUGE_TABLE_DEFAULT_SAMPLE_ROWS) + .hugeTableDefaultSampleRows; + } catch (Exception e) { + LOG.warn("Failed to get value of huge_table_default_sample_rows, return default", e); + } + return StatisticConstants.HUGE_TABLE_DEFAULT_SAMPLE_ROWS; + } + + public static long getHugeTableLowerBoundSizeInBytes() { + try { + return findConfigFromGlobalSessionVar(SessionVariable.HUGE_TABLE_LOWER_BOUND_SIZE_IN_BYTES) + .hugeTableLowerBoundSizeInBytes; + } catch (Exception e) { + LOG.warn("Failed to get value of huge_table_lower_bound_size_in_bytes, return default", e); + } + return StatisticConstants.HUGE_TABLE_LOWER_BOUND_SIZE_IN_BYTES; + } + + public static long getHugeTableAutoAnalyzeIntervalInMillis() { + try { + return findConfigFromGlobalSessionVar(SessionVariable.HUGE_TABLE_AUTO_ANALYZE_INTERVAL_IN_MILLIS) + .hugeTableAutoAnalyzeIntervalInMillis; + } catch (Exception e) { + LOG.warn("Failed to get value of huge_table_auto_analyze_interval_in_millis, return default", e); + } + return StatisticConstants.HUGE_TABLE_AUTO_ANALYZE_INTERVAL_IN_MILLIS; + } + + public static long getTableStatsHealthThreshold() { + try { + return findConfigFromGlobalSessionVar(SessionVariable.TABLE_STATS_HEALTH_THRESHOLD) + .tableStatsHealthThreshold; + } catch (Exception e) { + LOG.warn("Failed to get value of table_stats_health_threshold, return default", e); + } + return StatisticConstants.TABLE_STATS_HEALTH_THRESHOLD; + } + + public static int getAnalyzeTimeout() { + try { + return findConfigFromGlobalSessionVar(SessionVariable.ANALYZE_TIMEOUT) + .analyzeTimeoutS; + } catch (Exception e) { + LOG.warn("Failed to get value of table_stats_health_threshold, return default", e); + } + return StatisticConstants.ANALYZE_TIMEOUT_IN_SEC; + } + } diff --git a/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisJobTest.java b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisJobTest.java index f01485f642fac0..d4dedd17123807 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisJobTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisJobTest.java @@ -17,25 +17,10 @@ package org.apache.doris.statistics; -import org.apache.doris.catalog.Column; -import org.apache.doris.catalog.Database; -import org.apache.doris.catalog.InternalSchemaInitializer; -import org.apache.doris.catalog.OlapTable; -import org.apache.doris.catalog.PrimitiveType; -import org.apache.doris.common.FeConstants; -import org.apache.doris.datasource.InternalCatalog; -import org.apache.doris.qe.AutoCloseConnectContext; -import org.apache.doris.qe.ConnectContext; +import org.apache.doris.catalog.Env; import org.apache.doris.qe.StmtExecutor; -import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod; -import org.apache.doris.statistics.AnalysisInfo.AnalysisMode; -import org.apache.doris.statistics.AnalysisInfo.AnalysisType; -import org.apache.doris.statistics.AnalysisInfo.JobType; -import org.apache.doris.statistics.util.DBObjects; import org.apache.doris.statistics.util.StatisticsUtil; -import org.apache.doris.utframe.TestWithFeService; -import com.google.common.collect.Maps; import mockit.Expectations; import mockit.Mock; import mockit.MockUp; @@ -44,136 +29,196 @@ import org.junit.jupiter.api.Test; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -public class AnalysisJobTest extends TestWithFeService { - - @Override - protected void runBeforeAll() throws Exception { - try { - InternalSchemaInitializer.createDB(); - createDatabase("analysis_job_test"); - connectContext.setDatabase("default_cluster:analysis_job_test"); - createTable("CREATE TABLE t1 (col1 int not null, col2 int not null, col3 int not null)\n" - + "DISTRIBUTED BY HASH(col3)\n" + "BUCKETS 1\n" - + "PROPERTIES(\n" + " \"replication_num\"=\"1\"\n" - + ");"); - } catch (Exception e) { - throw new RuntimeException(e); - } - FeConstants.runningUnitTest = true; - } +import java.util.HashSet; +import java.util.concurrent.atomic.AtomicInteger; + +public class AnalysisJobTest { + // make user task has been set corresponding job @Test - public void testCreateAnalysisJob() throws Exception { + public void initTest(@Mocked AnalysisInfo jobInfo, @Mocked OlapAnalysisTask task) { + AnalysisJob analysisJob = new AnalysisJob(jobInfo, Arrays.asList(task)); + Assertions.assertSame(task.job, analysisJob); + } - new MockUp() { + @Test + public void testAppendBufTest1(@Mocked AnalysisInfo analysisInfo, @Mocked OlapAnalysisTask olapAnalysisTask) { + AtomicInteger writeBufInvokeTimes = new AtomicInteger(); + new MockUp() { + @Mock + protected void writeBuf() { + writeBufInvokeTimes.incrementAndGet(); + } @Mock - public AutoCloseConnectContext buildConnectContext() { - return new AutoCloseConnectContext(connectContext); + public void updateTaskState(AnalysisState state, String msg) { } @Mock - public void execUpdate(String sql) throws Exception { + public void deregisterJob() { } }; + AnalysisJob job = new AnalysisJob(analysisInfo, Arrays.asList(olapAnalysisTask)); + job.queryingTask = new HashSet<>(); + job.queryingTask.add(olapAnalysisTask); + job.queryFinished = new HashSet<>(); + job.buf = new ArrayList<>(); + job.totalTaskCount = 20; + + // not all task finished nor cached limit exceed, shouldn't write + job.appendBuf(olapAnalysisTask, Arrays.asList(new ColStatsData())); + Assertions.assertEquals(0, writeBufInvokeTimes.get()); + } - new MockUp() { + @Test + public void testAppendBufTest2(@Mocked AnalysisInfo analysisInfo, @Mocked OlapAnalysisTask olapAnalysisTask) { + AtomicInteger writeBufInvokeTimes = new AtomicInteger(); + AtomicInteger deregisterTimes = new AtomicInteger(); + + new MockUp() { @Mock - public List executeInternalQuery() { - return Collections.emptyList(); + protected void writeBuf() { + writeBufInvokeTimes.incrementAndGet(); } - }; - new MockUp() { + @Mock + public void updateTaskState(AnalysisState state, String msg) { + } @Mock - public ConnectContext get() { - return connectContext; + public void deregisterJob() { + deregisterTimes.getAndIncrement(); } }; - String sql = "ANALYZE TABLE t1"; - Assertions.assertNotNull(getSqlStmtExecutor(sql)); + AnalysisJob job = new AnalysisJob(analysisInfo, Arrays.asList(olapAnalysisTask)); + job.queryingTask = new HashSet<>(); + job.queryingTask.add(olapAnalysisTask); + job.queryFinished = new HashSet<>(); + job.buf = new ArrayList<>(); + job.totalTaskCount = 1; + + job.appendBuf(olapAnalysisTask, Arrays.asList(new ColStatsData())); + // all task finished, should write and deregister this job + Assertions.assertEquals(1, writeBufInvokeTimes.get()); + Assertions.assertEquals(1, deregisterTimes.get()); } @Test - public void testJobExecution(@Mocked StmtExecutor stmtExecutor, @Mocked InternalCatalog catalog, @Mocked - Database database, - @Mocked OlapTable olapTable) - throws Exception { - new MockUp() { + public void testAppendBufTest3(@Mocked AnalysisInfo analysisInfo, @Mocked OlapAnalysisTask olapAnalysisTask) { + AtomicInteger writeBufInvokeTimes = new AtomicInteger(); + new MockUp() { @Mock - public Column getColumn(String name) { - return new Column("col1", PrimitiveType.INT); + protected void writeBuf() { + writeBufInvokeTimes.incrementAndGet(); } - }; - - new MockUp() { @Mock - public ConnectContext buildConnectContext() { - return connectContext; + public void updateTaskState(AnalysisState state, String msg) { } @Mock - public void execUpdate(String sql) throws Exception { + public void deregisterJob() { } + }; + AnalysisJob job = new AnalysisJob(analysisInfo, Arrays.asList(olapAnalysisTask)); + job.queryingTask = new HashSet<>(); + job.queryingTask.add(olapAnalysisTask); + job.queryFinished = new HashSet<>(); + job.buf = new ArrayList<>(); + ColStatsData colStatsData = new ColStatsData(); + for (int i = 0; i < StatisticsUtil.getInsertMergeCount(); i++) { + job.buf.add(colStatsData); + } + job.totalTaskCount = 100; + + job.appendBuf(olapAnalysisTask, Arrays.asList(new ColStatsData())); + // cache limit exceed, should write them + Assertions.assertEquals(1, writeBufInvokeTimes.get()); + } + @Test + public void testUpdateTaskState( + @Mocked AnalysisInfo info, + @Mocked OlapAnalysisTask task1, + @Mocked OlapAnalysisTask task2) { + AtomicInteger updateTaskStatusInvokeTimes = new AtomicInteger(); + new MockUp() { @Mock - public DBObjects convertIdToObjects(long catalogId, long dbId, long tblId) { - return new DBObjects(catalog, database, olapTable); + public void updateTaskStatus(AnalysisInfo info, AnalysisState taskState, String message, long time) { + updateTaskStatusInvokeTimes.getAndIncrement(); } }; - new MockUp() { - + AnalysisManager analysisManager = new AnalysisManager(); + new MockUp() { @Mock - public void syncLoadColStats(long tableId, long idxId, String colName) { + public AnalysisManager getAnalysisManager() { + return analysisManager; } }; - new MockUp() { + AnalysisJob job = new AnalysisJob(info, Collections.singletonList(task1)); + job.queryFinished = new HashSet<>(); + job.queryFinished.add(task2); + job.updateTaskState(AnalysisState.FAILED, ""); + Assertions.assertEquals(2, updateTaskStatusInvokeTimes.get()); + } + @Test + public void testWriteBuf1(@Mocked AnalysisInfo info, + @Mocked OlapAnalysisTask task1, @Mocked OlapAnalysisTask task2) { + AnalysisJob job = new AnalysisJob(info, Collections.singletonList(task1)); + job.queryFinished = new HashSet<>(); + job.queryFinished.add(task2); + new MockUp() { @Mock - public void execute() throws Exception { - + public void updateTaskState(AnalysisState state, String msg) { } @Mock - public List executeInternalQuery() { - return new ArrayList<>(); - } - }; + protected void executeWithExceptionOnFail(StmtExecutor stmtExecutor) throws Exception { - new MockUp() { + } @Mock - public void execSQLs(List partitionAnalysisSQLs, Map params) throws Exception {} + protected void syncLoadStats() { + } }; - HashMap> colToPartitions = Maps.newHashMap(); - colToPartitions.put("col1", Collections.singleton("t1")); - AnalysisInfo analysisJobInfo = new AnalysisInfoBuilder().setJobId(0).setTaskId(0) - .setCatalogId(0) - .setDBId(0) - .setTblId(0) - .setColName("col1").setJobType(JobType.MANUAL) - .setAnalysisMode(AnalysisMode.FULL) - .setAnalysisMethod(AnalysisMethod.FULL) - .setAnalysisType(AnalysisType.FUNDAMENTALS) - .setColToPartitions(colToPartitions) - .setState(AnalysisState.RUNNING) - .build(); - new OlapAnalysisTask(analysisJobInfo).doExecute(); new Expectations() { { - stmtExecutor.execute(); + job.syncLoadStats(); times = 1; } }; + job.writeBuf(); + + Assertions.assertEquals(0, job.queryFinished.size()); + } + + @Test + public void testWriteBuf2(@Mocked AnalysisInfo info, + @Mocked OlapAnalysisTask task1, @Mocked OlapAnalysisTask task2) { + new MockUp() { + @Mock + public void updateTaskState(AnalysisState state, String msg) { + } + + @Mock + protected void executeWithExceptionOnFail(StmtExecutor stmtExecutor) throws Exception { + throw new RuntimeException(); + } + + @Mock + protected void syncLoadStats() { + } + }; + AnalysisJob job = new AnalysisJob(info, Collections.singletonList(task1)); + job.buf.add(new ColStatsData()); + job.queryFinished = new HashSet<>(); + job.queryFinished.add(task2); + job.writeBuf(); + Assertions.assertEquals(1, job.queryFinished.size()); } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisManagerTest.java b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisManagerTest.java index a0d72fcd4269a5..2e1b70fef25de6 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisManagerTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisManagerTest.java @@ -24,6 +24,7 @@ import org.apache.doris.catalog.Column; import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.PrimitiveType; +import org.apache.doris.common.Config; import org.apache.doris.common.DdlException; import org.apache.doris.statistics.AnalysisInfo.AnalysisType; import org.apache.doris.statistics.AnalysisInfo.JobType; @@ -340,7 +341,7 @@ public List getBaseSchema() { }; OlapTable olapTable = new OlapTable(); TableStatsMeta stats1 = new TableStatsMeta(0, 50, new AnalysisInfoBuilder().setColName("col1").build()); - stats1.updatedRows.addAndGet(30); + stats1.updatedRows.addAndGet(50); Assertions.assertTrue(olapTable.needReAnalyzeTable(stats1)); TableStatsMeta stats2 = new TableStatsMeta(0, 190, new AnalysisInfoBuilder().setColName("col1").build()); @@ -349,4 +350,38 @@ public List getBaseSchema() { } + @Test + public void testRecordLimit1() { + Config.analyze_record_limit = 2; + AnalysisManager analysisManager = new AnalysisManager(); + analysisManager.replayCreateAnalysisJob(new AnalysisInfoBuilder().setJobId(1).build()); + analysisManager.replayCreateAnalysisJob(new AnalysisInfoBuilder().setJobId(2).build()); + analysisManager.replayCreateAnalysisJob(new AnalysisInfoBuilder().setJobId(3).build()); + Assertions.assertEquals(2, analysisManager.analysisJobInfoMap.size()); + Assertions.assertTrue(analysisManager.analysisJobInfoMap.containsKey(2L)); + Assertions.assertTrue(analysisManager.analysisJobInfoMap.containsKey(3L)); + } + + @Test + public void testRecordLimit2() { + Config.analyze_record_limit = 2; + AnalysisManager analysisManager = new AnalysisManager(); + analysisManager.replayCreateAnalysisTask(new AnalysisInfoBuilder().setTaskId(1).build()); + analysisManager.replayCreateAnalysisTask(new AnalysisInfoBuilder().setTaskId(2).build()); + analysisManager.replayCreateAnalysisTask(new AnalysisInfoBuilder().setTaskId(3).build()); + Assertions.assertEquals(2, analysisManager.analysisTaskInfoMap.size()); + Assertions.assertTrue(analysisManager.analysisTaskInfoMap.containsKey(2L)); + Assertions.assertTrue(analysisManager.analysisTaskInfoMap.containsKey(3L)); + } + + @Test + public void testRecordLimit3() { + Config.analyze_record_limit = 2; + AnalysisManager analysisManager = new AnalysisManager(); + analysisManager.autoJobs.offer(new AnalysisInfoBuilder().setJobId(1).build()); + analysisManager.autoJobs.offer(new AnalysisInfoBuilder().setJobId(2).build()); + analysisManager.autoJobs.offer(new AnalysisInfoBuilder().setJobId(3).build()); + Assertions.assertEquals(2, analysisManager.autoJobs.size()); + } + } diff --git a/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisTaskExecutorTest.java b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisTaskExecutorTest.java index 19d7798041a114..8cfcfeabd28be0 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisTaskExecutorTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalysisTaskExecutorTest.java @@ -37,6 +37,7 @@ import mockit.Mock; import mockit.MockUp; import mockit.Mocked; +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; import java.util.Collections; @@ -45,6 +46,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.atomic.AtomicBoolean; public class AnalysisTaskExecutorTest extends TestWithFeService { @@ -82,6 +84,15 @@ public Column getColumn(String name) { return new Column("col1", PrimitiveType.INT); } }; + final AtomicBoolean cancelled = new AtomicBoolean(); + new MockUp() { + + @Mock + public boolean cancel(String msg) { + cancelled.set(true); + return true; + } + }; AnalysisInfo analysisJobInfo = new AnalysisInfoBuilder().setJobId(0).setTaskId(0) .setCatalogId(0) .setDBId(0) @@ -98,7 +109,10 @@ public Column getColumn(String name) { AnalysisTaskWrapper analysisTaskWrapper = new AnalysisTaskWrapper(analysisTaskExecutor, analysisJob); Deencapsulation.setField(analysisTaskWrapper, "startTime", 5); b.put(analysisTaskWrapper); - analysisTaskExecutor.start(); + analysisTaskExecutor.tryToCancel(); + Assertions.assertTrue(cancelled.get()); + Assertions.assertTrue(b.isEmpty()); + } @Test diff --git a/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalyzeTest.java b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalyzeTest.java new file mode 100644 index 00000000000000..268540885dac1d --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/AnalyzeTest.java @@ -0,0 +1,185 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.statistics; + +import org.apache.doris.catalog.Column; +import org.apache.doris.catalog.Database; +import org.apache.doris.catalog.InternalSchemaInitializer; +import org.apache.doris.catalog.OlapTable; +import org.apache.doris.catalog.PrimitiveType; +import org.apache.doris.common.FeConstants; +import org.apache.doris.datasource.InternalCatalog; +import org.apache.doris.qe.AutoCloseConnectContext; +import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.StmtExecutor; +import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod; +import org.apache.doris.statistics.AnalysisInfo.AnalysisMode; +import org.apache.doris.statistics.AnalysisInfo.AnalysisType; +import org.apache.doris.statistics.AnalysisInfo.JobType; +import org.apache.doris.statistics.util.DBObjects; +import org.apache.doris.statistics.util.StatisticsUtil; +import org.apache.doris.utframe.TestWithFeService; + +import com.google.common.collect.Maps; +import mockit.Expectations; +import mockit.Mock; +import mockit.MockUp; +import mockit.Mocked; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public class AnalyzeTest extends TestWithFeService { + + @Override + protected void runBeforeAll() throws Exception { + try { + InternalSchemaInitializer.createDB(); + createDatabase("analysis_job_test"); + connectContext.setDatabase("default_cluster:analysis_job_test"); + createTable("CREATE TABLE t1 (col1 int not null, col2 int not null, col3 int not null)\n" + + "DISTRIBUTED BY HASH(col3)\n" + "BUCKETS 1\n" + + "PROPERTIES(\n" + " \"replication_num\"=\"1\"\n" + + ");"); + } catch (Exception e) { + throw new RuntimeException(e); + } + FeConstants.runningUnitTest = true; + } + + @Test + public void testCreateAnalysisJob() throws Exception { + + new MockUp() { + + @Mock + public AutoCloseConnectContext buildConnectContext() { + return new AutoCloseConnectContext(connectContext); + } + + @Mock + public void execUpdate(String sql) throws Exception { + } + }; + + new MockUp() { + @Mock + public List executeInternalQuery() { + return Collections.emptyList(); + } + }; + + new MockUp() { + + @Mock + public ConnectContext get() { + return connectContext; + } + }; + String sql = "ANALYZE TABLE t1"; + Assertions.assertNotNull(getSqlStmtExecutor(sql)); + } + + @Test + public void testJobExecution(@Mocked StmtExecutor stmtExecutor, @Mocked InternalCatalog catalog, @Mocked + Database database, + @Mocked OlapTable olapTable) + throws Exception { + new MockUp() { + + @Mock + public Column getColumn(String name) { + return new Column("col1", PrimitiveType.INT); + } + }; + + new MockUp() { + + @Mock + public ConnectContext buildConnectContext() { + return connectContext; + } + + @Mock + public void execUpdate(String sql) throws Exception { + } + + @Mock + public DBObjects convertIdToObjects(long catalogId, long dbId, long tblId) { + return new DBObjects(catalog, database, olapTable); + } + }; + new MockUp() { + + @Mock + public void syncLoadColStats(long tableId, long idxId, String colName) { + } + }; + new MockUp() { + + @Mock + public void execute() throws Exception { + + } + + @Mock + public List executeInternalQuery() { + return new ArrayList<>(); + } + }; + + new MockUp() { + + @Mock + public void execSQLs(List partitionAnalysisSQLs, Map params) throws Exception {} + }; + + new MockUp() { + + @Mock + protected void runQuery(String sql) {} + }; + HashMap> colToPartitions = Maps.newHashMap(); + colToPartitions.put("col1", Collections.singleton("t1")); + AnalysisInfo analysisJobInfo = new AnalysisInfoBuilder().setJobId(0).setTaskId(0) + .setCatalogId(0) + .setDBId(0) + .setTblId(0) + .setColName("col1").setJobType(JobType.MANUAL) + .setAnalysisMode(AnalysisMode.FULL) + .setAnalysisMethod(AnalysisMethod.FULL) + .setAnalysisType(AnalysisType.FUNDAMENTALS) + .setColToPartitions(colToPartitions) + .setState(AnalysisState.RUNNING) + .build(); + new OlapAnalysisTask(analysisJobInfo).doExecute(); + new Expectations() { + { + stmtExecutor.execute(); + times = 1; + } + }; + } + +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/statistics/CacheTest.java b/fe/fe-core/src/test/java/org/apache/doris/statistics/CacheTest.java index cb0364682c13a7..95ed5023e3652b 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/statistics/CacheTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/CacheTest.java @@ -23,6 +23,7 @@ import org.apache.doris.catalog.Type; import org.apache.doris.catalog.external.HMSExternalDatabase; import org.apache.doris.catalog.external.HMSExternalTable; +import org.apache.doris.common.ThreadPoolManager; import org.apache.doris.datasource.CatalogMgr; import org.apache.doris.datasource.HMSExternalCatalog; import org.apache.doris.ha.FrontendNodeType; @@ -31,6 +32,9 @@ import org.apache.doris.thrift.TUpdateFollowerStatsCacheRequest; import org.apache.doris.utframe.TestWithFeService; +import com.github.benmanes.caffeine.cache.AsyncCacheLoader; +import com.github.benmanes.caffeine.cache.AsyncLoadingCache; +import com.github.benmanes.caffeine.cache.Caffeine; import com.google.common.collect.Lists; import com.google.gson.JsonArray; import com.google.gson.JsonElement; @@ -40,9 +44,11 @@ import mockit.Mock; import mockit.MockUp; import mockit.Mocked; +import org.checkerframework.checker.nullness.qual.NonNull; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -50,6 +56,7 @@ import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; public class CacheTest extends TestWithFeService { @@ -199,10 +206,10 @@ public List execStatisticQuery(String sql) { @Test public void testLoadFromMeta(@Mocked Env env, - @Mocked CatalogMgr mgr, - @Mocked HMSExternalCatalog catalog, - @Mocked HMSExternalDatabase db, - @Mocked HMSExternalTable table) throws Exception { + @Mocked CatalogMgr mgr, + @Mocked HMSExternalCatalog catalog, + @Mocked HMSExternalDatabase db, + @Mocked HMSExternalTable table) throws Exception { new MockUp() { @Mock @@ -350,4 +357,29 @@ private void sendStats(Frontend frontend, } }; } + + @Test + public void testEvict() { + ThreadPoolExecutor threadPool + = ThreadPoolManager.newDaemonFixedThreadPool( + 1, Integer.MAX_VALUE, "STATS_FETCH", true); + AsyncLoadingCache columnStatisticsCache = + Caffeine.newBuilder() + .maximumSize(1) + .refreshAfterWrite(Duration.ofHours(StatisticConstants.STATISTICS_CACHE_REFRESH_INTERVAL)) + .executor(threadPool) + .buildAsync(new AsyncCacheLoader() { + @Override + public @NonNull CompletableFuture asyncLoad(@NonNull Integer integer, + @NonNull Executor executor) { + return CompletableFuture.supplyAsync(() -> { + return integer; + }, threadPool); + } + }); + columnStatisticsCache.get(1); + columnStatisticsCache.get(2); + Assertions.assertTrue(columnStatisticsCache.synchronous().asMap().containsKey(2)); + Assertions.assertEquals(1, columnStatisticsCache.synchronous().asMap().size()); + } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/statistics/OlapAnalysisTaskTest.java b/fe/fe-core/src/test/java/org/apache/doris/statistics/OlapAnalysisTaskTest.java index d618a5fa5380db..f2b9f84f0d0e7d 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/statistics/OlapAnalysisTaskTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/OlapAnalysisTaskTest.java @@ -19,47 +19,36 @@ import org.apache.doris.analysis.TableSample; import org.apache.doris.catalog.DatabaseIf; +import org.apache.doris.catalog.OlapTable; import org.apache.doris.catalog.TableIf; -import org.apache.doris.common.Config; import org.apache.doris.datasource.CatalogIf; import org.apache.doris.statistics.AnalysisInfo.AnalysisMethod; +import org.apache.doris.statistics.AnalysisInfo.JobType; +import org.apache.doris.statistics.util.StatisticsUtil; -import mockit.Expectations; +import mockit.Mock; +import mockit.MockUp; import mockit.Mocked; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class OlapAnalysisTaskTest { + // test manual @Test - public void testAutoSample(@Mocked CatalogIf catalogIf, @Mocked DatabaseIf databaseIf, @Mocked TableIf tableIf) { - new Expectations() { - { - tableIf.getDataSize(true); - result = 60_0000_0000L; - } - }; + public void testSample1(@Mocked CatalogIf catalogIf, @Mocked DatabaseIf databaseIf, @Mocked TableIf tableIf) { AnalysisInfoBuilder analysisInfoBuilder = new AnalysisInfoBuilder() .setAnalysisMethod(AnalysisMethod.FULL); + analysisInfoBuilder.setJobType(JobType.MANUAL); OlapAnalysisTask olapAnalysisTask = new OlapAnalysisTask(); olapAnalysisTask.info = analysisInfoBuilder.build(); olapAnalysisTask.tbl = tableIf; - Config.enable_auto_sample = true; TableSample tableSample = olapAnalysisTask.getTableSample(); - Assertions.assertEquals(4194304, tableSample.getSampleValue()); - Assertions.assertFalse(tableSample.isPercent()); - - new Expectations() { - { - tableIf.getDataSize(true); - result = 1_0000_0000L; - } - }; - tableSample = olapAnalysisTask.getTableSample(); Assertions.assertNull(tableSample); analysisInfoBuilder.setSampleRows(10); + analysisInfoBuilder.setJobType(JobType.MANUAL); analysisInfoBuilder.setAnalysisMethod(AnalysisMethod.SAMPLE); olapAnalysisTask.info = analysisInfoBuilder.build(); tableSample = olapAnalysisTask.getTableSample(); @@ -67,4 +56,49 @@ public void testAutoSample(@Mocked CatalogIf catalogIf, @Mocked DatabaseIf datab Assertions.assertFalse(tableSample.isPercent()); } + // test auto big table + @Test + public void testSample2(@Mocked OlapTable tbl) { + new MockUp() { + + @Mock + public long getDataSize(boolean singleReplica) { + return 1000_0000_0000L; + } + }; + + AnalysisInfoBuilder analysisInfoBuilder = new AnalysisInfoBuilder() + .setAnalysisMethod(AnalysisMethod.FULL); + analysisInfoBuilder.setJobType(JobType.SYSTEM); + OlapAnalysisTask olapAnalysisTask = new OlapAnalysisTask(); + olapAnalysisTask.info = analysisInfoBuilder.build(); + olapAnalysisTask.tbl = tbl; + TableSample tableSample = olapAnalysisTask.getTableSample(); + Assertions.assertNotNull(tableSample); + Assertions.assertEquals(StatisticsUtil.getHugeTableSampleRows(), tableSample.getSampleValue()); + + } + + // test auto small table + @Test + public void testSample3(@Mocked OlapTable tbl) { + new MockUp() { + + @Mock + public long getDataSize(boolean singleReplica) { + return 1000; + } + }; + + AnalysisInfoBuilder analysisInfoBuilder = new AnalysisInfoBuilder() + .setAnalysisMethod(AnalysisMethod.FULL); + analysisInfoBuilder.setJobType(JobType.SYSTEM); + OlapAnalysisTask olapAnalysisTask = new OlapAnalysisTask(); + olapAnalysisTask.info = analysisInfoBuilder.build(); + olapAnalysisTask.tbl = tbl; + TableSample tableSample = olapAnalysisTask.getTableSample(); + Assertions.assertNull(tableSample); + + } + } diff --git a/fe/fe-core/src/test/java/org/apache/doris/statistics/StatisticsAutoCollectorTest.java b/fe/fe-core/src/test/java/org/apache/doris/statistics/StatisticsAutoCollectorTest.java index 5ddd207bab7409..d441ce5b09db98 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/statistics/StatisticsAutoCollectorTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/StatisticsAutoCollectorTest.java @@ -27,6 +27,7 @@ import org.apache.doris.catalog.Type; import org.apache.doris.catalog.View; import org.apache.doris.cluster.ClusterNamespace; +import org.apache.doris.common.Config; import org.apache.doris.common.DdlException; import org.apache.doris.common.FeConstants; import org.apache.doris.datasource.CatalogIf; @@ -40,10 +41,12 @@ import mockit.Injectable; import mockit.Mock; import mockit.MockUp; +import mockit.Mocked; import org.apache.hadoop.util.Lists; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; +import java.time.LocalTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -52,6 +55,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; public class StatisticsAutoCollectorTest { @@ -213,4 +217,73 @@ public AnalysisInfo getAnalysisJobInfo(AnalysisInfo jobInfo, TableIf table, // Assertions.assertNull(statisticsAutoCollector.getReAnalyzeRequiredPart(analysisInfo2)); Assertions.assertNotNull(statisticsAutoCollector.getReAnalyzeRequiredPart(analysisInfo2)); } + + @Test + public void testLoop() { + AtomicBoolean timeChecked = new AtomicBoolean(); + AtomicBoolean switchChecked = new AtomicBoolean(); + new MockUp() { + + @Mock + public boolean inAnalyzeTime(LocalTime now) { + timeChecked.set(true); + return true; + } + + @Mock + public boolean enableAutoAnalyze() { + switchChecked.set(true); + return true; + } + }; + StatisticsAutoCollector autoCollector = new StatisticsAutoCollector(); + autoCollector.collect(); + Assertions.assertTrue(timeChecked.get() && switchChecked.get()); + + } + + @Test + public void checkAvailableThread() { + StatisticsAutoCollector autoCollector = new StatisticsAutoCollector(); + Assertions.assertEquals(Config.full_auto_analyze_simultaneously_running_task_num, + autoCollector.analysisTaskExecutor.executors.getMaximumPoolSize()); + } + + @Test + public void testSkip(@Mocked OlapTable olapTable, @Mocked TableStatsMeta stats, @Mocked TableIf anyOtherTable) { + new MockUp() { + + @Mock + public long getDataSize(boolean singleReplica) { + return StatisticsUtil.getHugeTableLowerBoundSizeInBytes() * 5 + 1000000000; + } + }; + + new MockUp() { + + @Mock + public TableStatsMeta findTableStatsStatus(long tblId) { + return stats; + } + }; + // A very huge table has been updated recently, so we should skip it this time + stats.updatedTime = System.currentTimeMillis() - 1000; + StatisticsAutoCollector autoCollector = new StatisticsAutoCollector(); + Assertions.assertTrue(autoCollector.skip(olapTable)); + // The update of this huge table is long time ago, so we shouldn't skip it this time + stats.updatedTime = System.currentTimeMillis() + - StatisticsUtil.getHugeTableAutoAnalyzeIntervalInMillis() - 10000; + Assertions.assertFalse(autoCollector.skip(olapTable)); + new MockUp() { + + @Mock + public TableStatsMeta findTableStatsStatus(long tblId) { + return null; + } + }; + // can't find table stats meta, which means this table never get analyzed, so we shouldn't skip it this time + Assertions.assertFalse(autoCollector.skip(olapTable)); + // this is not olap table nor external table, so we should skip it this time + Assertions.assertTrue(autoCollector.skip(anyOtherTable)); + } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/statistics/util/StatisticsUtilTest.java b/fe/fe-core/src/test/java/org/apache/doris/statistics/util/StatisticsUtilTest.java index c0d4a656d75565..c0c790c9c25dff 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/statistics/util/StatisticsUtilTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/statistics/util/StatisticsUtilTest.java @@ -19,9 +19,15 @@ import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; +import org.apache.doris.qe.SessionVariable; -import org.junit.Test; +import mockit.Mock; +import mockit.MockUp; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.time.LocalTime; +import java.time.format.DateTimeFormatter; public class StatisticsUtilTest { @Test @@ -67,4 +73,42 @@ public void testConvertToDouble() { Assertions.fail(); } } + + @Test + public void testInAnalyzeTime1() { + new MockUp() { + + @Mock + protected SessionVariable findConfigFromGlobalSessionVar(String varName) throws Exception { + SessionVariable sessionVariable = new SessionVariable(); + sessionVariable.fullAutoAnalyzeStartTime = "00:00:00"; + sessionVariable.fullAutoAnalyzeEndTime = "02:00:00"; + return sessionVariable; + } + }; + DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); + String now = "01:00:00"; + Assertions.assertTrue(StatisticsUtil.inAnalyzeTime(LocalTime.parse(now, timeFormatter))); + now = "13:00:00"; + Assertions.assertFalse(StatisticsUtil.inAnalyzeTime(LocalTime.parse(now, timeFormatter))); + } + + @Test + public void testInAnalyzeTime2() { + new MockUp() { + + @Mock + protected SessionVariable findConfigFromGlobalSessionVar(String varName) throws Exception { + SessionVariable sessionVariable = new SessionVariable(); + sessionVariable.fullAutoAnalyzeStartTime = "00:00:00"; + sessionVariable.fullAutoAnalyzeEndTime = "23:00:00"; + return sessionVariable; + } + }; + DateTimeFormatter timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss"); + String now = "15:00:00"; + Assertions.assertTrue(StatisticsUtil.inAnalyzeTime(LocalTime.parse(now, timeFormatter))); + now = "23:30:00"; + Assertions.assertFalse(StatisticsUtil.inAnalyzeTime(LocalTime.parse(now, timeFormatter))); + } } diff --git a/regression-test/suites/statistics/analyze_stats.groovy b/regression-test/suites/statistics/analyze_stats.groovy index 4e4c4a08425944..92692559193341 100644 --- a/regression-test/suites/statistics/analyze_stats.groovy +++ b/regression-test/suites/statistics/analyze_stats.groovy @@ -57,7 +57,11 @@ suite("test_analyze") { `analyzetestlimitedk8` double null comment "", `analyzetestlimitedk9` float null comment "", `analyzetestlimitedk12` string null comment "", - `analyzetestlimitedk13` largeint(40) null comment "" + `analyzetestlimitedk13` largeint(40) null comment "", + `analyzetestlimitedk14` ARRAY NULL COMMENT "", + `analyzetestlimitedk15` Map NULL COMMENT "", + `analyzetestlimitedk16` STRUCT NULL, + `analyzetestlimitedk17` JSON NULL ) engine=olap DUPLICATE KEY(`analyzetestlimitedk3`) DISTRIBUTED BY HASH(`analyzetestlimitedk3`) BUCKETS 5 properties("replication_num" = "1") @@ -67,26 +71,39 @@ suite("test_analyze") { INSERT INTO `${tbl}` VALUES (-2103297891,1,101,15248,4761818404925265645,939926.283, 'UTmCFKMbprf0zSVOIlBJRNOl3JcNBdOsnCDt','2022-09-28','2022-10-28 01:56:56','tVvGDSrN6kyn', -954349107.187117,-40.46286,'g1ZP9nqVgaGKya3kPERdBofTWJQ4TIJEz972Xvw4hfPpTpWwlmondiLVTCyld7rSBlSWrE7NJRB0pvPGEFQKOx1s3', - '-1559301292834325905'), + '-1559301292834325905', NULL, NULL, NULL, NULL), (-2094982029,0,-81,-14746,-2618177187906633064,121889.100,NULL,'2023-05-01','2022-11-25 00:24:12', '36jVI0phYfhFucAOEASbh4OdvUYcI7QZFgQSveNyfGcRRUtQG9HGN1UcCmUH',-82250254.174239,NULL, - 'bTUHnMC4v7dI8U3TK0z4wZHdytjfHQfF1xKdYAVwPVNMT4fT4F92hj8ENQXmCkWtfp','6971810221218612372'), + 'bTUHnMC4v7dI8U3TK0z4wZHdytjfHQfF1xKdYAVwPVNMT4fT4F92hj8ENQXmCkWtfp','6971810221218612372', NULL, NULL, NULL, NULL), (-1840301109,1,NULL,NULL,7805768460922079440,546556.220,'wC7Pif9SJrg9b0wicGfPz2ezEmEKotmN6AMI',NULL, '2023-05-20 18:13:14','NM5SLu62SGeuD',-1555800813.9748349,-11122.953, - 'NH97wIjXk7dspvvfUUKe41ZetUnDmqLxGg8UYXwOwK3Jlu7dxO2GE9UJjyKW0NBxqUk1DY','-5004534044262380098'), + 'NH97wIjXk7dspvvfUUKe41ZetUnDmqLxGg8UYXwOwK3Jlu7dxO2GE9UJjyKW0NBxqUk1DY','-5004534044262380098', NULL, NULL, NULL, NULL), (-1819679967,0,10,NULL,-5772413527188525359,-532045.626,'kqMe4VYEZAmajLthCLRkl8StDQHKrDWz91AQ','2022-06-30', '2023-02-22 15:30:38','wAbeF3p84j5pFJTInQuKZOezFbsy8HIjmuUF',-1766437367.4377379,1791.4128, - '6OWmBD04UeKt1xI2XnR8t1kPG7qEYrf4J8RkA8UMs4HF33Yl','-8433424551792664598'), + '6OWmBD04UeKt1xI2XnR8t1kPG7qEYrf4J8RkA8UMs4HF33Yl','-8433424551792664598', NULL, NULL, NULL, NULL), (-1490846276,0,NULL,7744,6074522476276146996,594200.976,NULL,'2022-11-27','2023-03-11 21:28:44', 'yr8AuJLr2ud7DIwlt06cC7711UOsKslcDyySuqqfQE5X7Vjic6azHOrM6W',-715849856.288922,3762.217, - '4UpWZJ0Twrefw0Tm0AxFS38V5','7406302706201801560'),(-1465848366,1,72,29170,-5585523608136628843,-34210.874, + '4UpWZJ0Twrefw0Tm0AxFS38V5','7406302706201801560', NULL, NULL, NULL, NULL),(-1465848366,1,72,29170,-5585523608136628843,-34210.874, 'rMGygAWU91Wa3b5A7l1wheo6EF0o6zhw4YeE','2022-09-20','2023-06-11 18:17:16','B6m9S9O2amsa4SXrEKK0ivJ2x9m1u8av', - 862085772.298349,-22304.209,'1','-3399178642401166400'),(-394034614,1,65,5393,-200651968801088119,NULL, + 862085772.298349,-22304.209,'1','-3399178642401166400', NULL, NULL, NULL, NULL),(-394034614,1,65,5393,-200651968801088119,NULL, '9MapWX9pn8zes9Gey1lhRsH3ATyQPIysjQYi','2023-05-11','2022-07-02 02:56:53','z5VWbuKr6HiK7yC7MRIoQGrb98VUS', - 1877828963.091433,-1204.1926,'fSDQqT38rkrJEi6fwc90rivgQcRPaW5V1aEmZpdSvUm','8882970420609470903'), + 1877828963.091433,-1204.1926,'fSDQqT38rkrJEi6fwc90rivgQcRPaW5V1aEmZpdSvUm','8882970420609470903', NULL, NULL, NULL, NULL), (-287465855,0,-10,-32484,-5161845307234178602,748718.592,'n64TXbG25DQL5aw5oo9o9cowSjHCXry9HkId','2023-01-02', '2022-11-17 14:58:52','d523m4PwLdHZtPTqSoOBo5IGivCKe4A1Sc8SKCILFxgzYLe0',NULL,27979.855, - 'ps7qwcZjBjkGfcXYMw5HQMwnElzoHqinwk8vhQCbVoGBgfotc4oSkpD3tP34h4h0tTogDMwFu60iJm1bofUzyUQofTeRwZk8','4692206687866847780') + 'ps7qwcZjBjkGfcXYMw5HQMwnElzoHqinwk8vhQCbVoGBgfotc4oSkpD3tP34h4h0tTogDMwFu60iJm1bofUzyUQofTeRwZk8','4692206687866847780', NULL, NULL, NULL, NULL) + """ + + sql """ + SET enable_nereids_planner=true; + + """ + + sql """ + SET forbid_unknown_col_stats=false; + """ + + sql """ + SELECT * FROM ${tbl} """ sql """ @@ -97,10 +114,6 @@ suite("test_analyze") { ANALYZE DATABASE ${db} WITH SYNC """ - sql """ - SET enable_nereids_planner=true; - - """ sql """ SET enable_fallback_to_original_planner=false; """ @@ -152,19 +165,19 @@ suite("test_analyze") { exception = e } - a_result_1 = sql """ + def a_result_1 = sql """ ANALYZE DATABASE ${db} WITH SYNC WITH SAMPLE PERCENT 10 """ - a_result_2 = sql """ + def a_result_2 = sql """ ANALYZE DATABASE ${db} WITH SYNC WITH SAMPLE PERCENT 5 """ - a_result_3 = sql """ + def a_result_3 = sql """ ANALYZE DATABASE ${db} WITH SAMPLE PERCENT 5 """ - show_result = sql """ + def show_result = sql """ SHOW ANALYZE """ @@ -891,8 +904,24 @@ PARTITION `p599` VALUES IN (599) } assert expected_col_stats(id_col_stats, 600, 1) - assert expected_col_stats(id_col_stats, 599, 7) + assert (int) Double.parseDouble(id_col_stats[0][2]) < 700 + && (int) Double.parseDouble(id_col_stats[0][2]) > 500 + assert expected_col_stats(id_col_stats, 0, 3) + assert expected_col_stats(id_col_stats, 2400, 4) + assert expected_col_stats(id_col_stats, 4, 5) assert expected_col_stats(id_col_stats, 0, 6) + assert expected_col_stats(id_col_stats, 599, 7) + + def update_time = id_col_stats[0][8] + + sql """ANALYZE TABLE test_600_partition_table_analyze WITH SYNC""" + + // Data has no change, update time shouldn't be update since this table don't need to analyze again + id_col_stats_2 = sql """ + SHOW COLUMN CACHED STATS test_600_partition_table_analyze(id); + """ + + assert update_time == id_col_stats_2[0][8] sql """DROP TABLE IF EXISTS increment_analyze_test""" sql """ @@ -1151,4 +1180,39 @@ PARTITION `p599` VALUES IN (599) return (r[0][7]).equals(expected_value) } expected_max(max, "测试") + + show_result = sql """ + SHOW ANALYZE ${tbl} + """ + + def tbl_name_as_expetected = { r,name -> + for (int i = 0; i < r.size; i++) { + if (r[i][3] != name) { + return false + } + } + return true + } + + assert show_result[0][9] == "FINISHED" + assert tbl_name_as_expetected(show_result, "${tbl}") + + show_result = sql """ + SHOW ANALYZE ${tbl} WHERE STATE = "FINISHED" + """ + + assert show_result.size() > 0 + + def all_finished = { r -> + for (int i = 0; i < r.size; i++) { + if (r[i][9] != "FINISHED") { + return false + } + } + return true + } + + assert all_finished(show_result) + + } diff --git a/regression-test/suites/statistics/test_agg_complex_type.groovy b/regression-test/suites/statistics/test_agg_complex_type.groovy new file mode 100644 index 00000000000000..55af87f35bd632 --- /dev/null +++ b/regression-test/suites/statistics/test_agg_complex_type.groovy @@ -0,0 +1,53 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_analyze_with_agg_complex_type") { + sql """drop table if exists test_agg_complex_type;""" + + sql """create table test_agg_complex_type ( + datekey int, + device_id bitmap BITMAP_UNION NULL, + hll_test hll hll_union, + qs QUANTILE_STATE QUANTILE_UNION + ) + aggregate key (datekey) + distributed by hash(datekey) buckets 1 + properties( + "replication_num" = "1" + );""" + + sql """insert into test_agg_complex_type values (1,to_bitmap(1), hll_hash("11"), TO_QUANTILE_STATE("11", 1.0));""" + + sql """insert into test_agg_complex_type values (2, to_bitmap(1), hll_hash("12"), TO_QUANTILE_STATE("11", 1.0));""" + + sql """ANALYZE TABLE test_agg_complex_type WITH SYNC""" + + def show_result = sql """SHOW COLUMN CACHED STATS test_agg_complex_type""" + + assert show_result.size() == 1 + + def expected_col_stats = { r, expected_value, idx -> + return (int) Double.parseDouble(r[0][idx]) == expected_value + } + + assert expected_col_stats(show_result, 2, 1) + assert expected_col_stats(show_result, 0, 3) + assert expected_col_stats(show_result, 8, 4) + assert expected_col_stats(show_result, 4, 5) + assert expected_col_stats(show_result, 1, 6) + assert expected_col_stats(show_result, 2, 7) +} \ No newline at end of file From c93c8f6105b33ea05c50eee00f60fff20b992cdd Mon Sep 17 00:00:00 2001 From: minghong Date: Wed, 8 Nov 2023 11:04:08 +0800 Subject: [PATCH 31/88] [opt](nereids) make AGG_SCALAR_SUBQUERY_TO_WINDOW_FUNCTION rewrite rule #25969 --- .../org/apache/doris/nereids/jobs/executor/Rewriter.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java index 7ce4ef267ad2d4..fe6bc13b6c4fe0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/jobs/executor/Rewriter.java @@ -151,10 +151,8 @@ public class Rewriter extends AbstractBatchJobExecutor { // we need run the following 2 rules to make AGG_SCALAR_SUBQUERY_TO_WINDOW_FUNCTION work bottomUp(new PullUpProjectUnderApply()), topDown(new PushdownFilterThroughProject()), - costBased( - custom(RuleType.AGG_SCALAR_SUBQUERY_TO_WINDOW_FUNCTION, - AggScalarSubQueryToWindowFunction::new) - ), + custom(RuleType.AGG_SCALAR_SUBQUERY_TO_WINDOW_FUNCTION, + AggScalarSubQueryToWindowFunction::new), bottomUp( new EliminateUselessPlanUnderApply(), // CorrelateApplyToUnCorrelateApply and ApplyToJoin From 47ba4aaf30b857d4b55f67c86f1a3dfcd154f66a Mon Sep 17 00:00:00 2001 From: zclllyybb Date: Wed, 8 Nov 2023 11:22:40 +0800 Subject: [PATCH 32/88] [Enhancement](load) add timer and partitions number limit (#26549) add timer and partitions number limit --- be/src/runtime/tablets_channel.cpp | 8 ++++---- be/src/runtime/tablets_channel.h | 1 + docs/en/docs/admin-manual/config/fe-config.md | 8 +++++++- docs/zh-CN/docs/admin-manual/config/fe-config.md | 10 ++++++++-- .../main/java/org/apache/doris/common/Config.java | 7 +++++++ .../java/org/apache/doris/catalog/OlapTable.java | 4 ++++ .../apache/doris/service/FrontendServiceImpl.java | 13 +++++++++++++ 7 files changed, 44 insertions(+), 7 deletions(-) diff --git a/be/src/runtime/tablets_channel.cpp b/be/src/runtime/tablets_channel.cpp index 91294135a06d8f..68a35ccc109392 100644 --- a/be/src/runtime/tablets_channel.cpp +++ b/be/src/runtime/tablets_channel.cpp @@ -84,6 +84,7 @@ void TabletsChannel::_init_profile(RuntimeProfile* profile) { _slave_replica_timer = ADD_TIMER(_profile, "SlaveReplicaTime"); _add_batch_timer = ADD_TIMER(_profile, "AddBatchTime"); _write_block_timer = ADD_TIMER(_profile, "WriteBlockTime"); + _incremental_open_timer = ADD_TIMER(_profile, "IncrementalOpenTabletTime"); _memory_usage_counter = memory_usage->AddHighWaterMarkCounter("Total", TUnit::BYTES); _write_memory_usage_counter = memory_usage->AddHighWaterMarkCounter("Write", TUnit::BYTES); _flush_memory_usage_counter = memory_usage->AddHighWaterMarkCounter("Flush", TUnit::BYTES); @@ -120,13 +121,14 @@ Status TabletsChannel::open(const PTabletWriterOpenRequest& request) { } Status TabletsChannel::incremental_open(const PTabletWriterOpenRequest& params) { + SCOPED_TIMER(_incremental_open_timer); if (_state == kInitialized) { // haven't opened return open(params); } std::lock_guard l(_lock); std::vector* index_slots = nullptr; int32_t schema_hash = 0; - for (auto& index : _schema->indexes()) { + for (const auto& index : _schema->indexes()) { if (index->index_id == _index_id) { index_slots = &index->slots; schema_hash = index->schema_hash; @@ -137,14 +139,12 @@ Status TabletsChannel::incremental_open(const PTabletWriterOpenRequest& params) return Status::InternalError("unknown index id, key={}", _key.to_string()); } // update tablets - std::vector tablet_ids; - tablet_ids.reserve(params.tablets_size()); size_t incremental_tablet_num = 0; std::stringstream ss; ss << "LocalTabletsChannel txn_id: " << _txn_id << " load_id: " << print_id(params.id()) << " incremental open delta writer: "; - for (auto& tablet : params.tablets()) { + for (const auto& tablet : params.tablets()) { if (_tablet_writers.find(tablet.tablet_id()) != _tablet_writers.end()) { continue; } diff --git a/be/src/runtime/tablets_channel.h b/be/src/runtime/tablets_channel.h index fe9c226829d794..4dca9050331cf2 100644 --- a/be/src/runtime/tablets_channel.h +++ b/be/src/runtime/tablets_channel.h @@ -196,6 +196,7 @@ class TabletsChannel { RuntimeProfile::Counter* _slave_replica_timer = nullptr; RuntimeProfile::Counter* _add_batch_timer = nullptr; RuntimeProfile::Counter* _write_block_timer = nullptr; + RuntimeProfile::Counter* _incremental_open_timer = nullptr; }; template diff --git a/docs/en/docs/admin-manual/config/fe-config.md b/docs/en/docs/admin-manual/config/fe-config.md index bb54a4fe692f83..11eab194221477 100644 --- a/docs/en/docs/admin-manual/config/fe-config.md +++ b/docs/en/docs/admin-manual/config/fe-config.md @@ -167,7 +167,7 @@ Default:100 the max txn number which bdbje can rollback when trying to rejoin the group -### `grpc_threadmgr_threads_nums` +#### `grpc_threadmgr_threads_nums` Default: 4096 @@ -2763,3 +2763,9 @@ Forbid LocalDeployManager drop nodes to prevent errors in the cluster.info file Default: mysql To ensure compatibility with the MySQL ecosystem, Doris includes a built-in database called mysql. If this database conflicts with a user's own database, please modify this field to replace the name of the Doris built-in MySQL database with a different name. + +#### `max_auto_partition_num` + +Default value: 2000 + +For auto-partitioned tables to prevent users from accidentally creating a large number of partitions, the number of partitions allowed per OLAP table is `max_auto_partition_num`. Default 2000. diff --git a/docs/zh-CN/docs/admin-manual/config/fe-config.md b/docs/zh-CN/docs/admin-manual/config/fe-config.md index 82c718a9a7b54b..9da440ada3d613 100644 --- a/docs/zh-CN/docs/admin-manual/config/fe-config.md +++ b/docs/zh-CN/docs/admin-manual/config/fe-config.md @@ -173,7 +173,7 @@ Doris 元数据将保存在这里。 强烈建议将此目录的存储为: 元数据会同步写入到多个 Follower FE,这个参数用于控制 Master FE 等待 Follower FE 发送 ack 的超时时间。当写入的数据较大时,可能 ack 时间较长,如果超时,会导致写元数据失败,FE 进程退出。此时可以适当调大这个参数。 -### `grpc_threadmgr_threads_nums` +#### `grpc_threadmgr_threads_nums` 默认值: 4096 @@ -2759,6 +2759,12 @@ show data (其他用法:HELP SHOW DATA) #### `mysqldb_replace_name` -Default: mysql +默认值:mysql Doris 为了兼用 mysql 周边工具生态,会内置一个名为 mysql 的数据库,如果该数据库与用户自建数据库冲突,请修改这个字段,为 doris 内置的 mysql database 更换一个名字 + +#### `max_auto_partition_num` + +默认值:2000 + +对于自动分区表,防止用户意外创建大量分区,每个OLAP表允许的分区数量为`max_auto_partition_num`。默认2000。 diff --git a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java index c6970c7d17067e..f11ddd1fafc4de 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java +++ b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java @@ -2249,4 +2249,11 @@ public class Config extends ConfigBase { @ConfField(mutable = true, masterOnly = true) public static int publish_topic_info_interval_ms = 30000; // 30s + + @ConfField(mutable = true, masterOnly = true, description = { + "对于自动分区表,防止用户意外创建大量分区,每个OLAP表允许的分区数量为`max_auto_partition_num`。默认2000。", + "For auto-partitioned tables to prevent users from accidentally creating a large number of partitions, " + + "the number of partitions allowed per OLAP table is `max_auto_partition_num`. Default 2000." + }) + public static int max_auto_partition_num = 2000; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java index d9501f0f1d4a8e..2e0df9cb3b68de 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/OlapTable.java @@ -964,6 +964,10 @@ public Partition getPartition(long partitionId) { return partition; } + public int getPartitionNum() { + return idToPartition.size(); + } + // get all partitions except temp partitions public Collection getPartitions() { return idToPartition.values(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java index 6ef0956808be1f..4cea18424f943b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java +++ b/fe/fe-core/src/main/java/org/apache/doris/service/FrontendServiceImpl.java @@ -3295,6 +3295,19 @@ public TCreatePartitionResult createPartition(TCreatePartitionRequest request) t return result; } + // check partition's number limit. + int partitionNum = olapTable.getPartitionNum() + addPartitionClauseMap.size(); + if (partitionNum > Config.max_auto_partition_num) { + olapTable.writeUnlock(); + String errorMessage = String.format( + "create partition failed. partition numbers %d will exceed limit variable max_auto_partition_num%d", + partitionNum, Config.max_auto_partition_num); + LOG.warn(errorMessage); + errorStatus.setErrorMsgs(Lists.newArrayList(errorMessage)); + result.setStatus(errorStatus); + return result; + } + for (AddPartitionClause addPartitionClause : addPartitionClauseMap.values()) { try { // here maybe check and limit created partitions num From f4cbbe64291ddbf06c9759b9a6ee0aef309034d0 Mon Sep 17 00:00:00 2001 From: Adonis Ling Date: Wed, 8 Nov 2023 11:23:13 +0800 Subject: [PATCH 33/88] [chore](workflow) Fix security issues with pull_request_target (#26525) In the workflow Code Checks, we use the event pull_request_target which has write permission to enable the actions to comment on our PRs. We should be careful with the write permission and must forbid from running any user code. The previous PR #24761 tried its best to achieve this goal. However, there is a scenario lacking of consideration (See #26494). #26494 attacks the workflow by git submodule way. This PR fixes this scenario by checkouting the external action explicitly in the workflow. --- .github/actions/action-sh-checker | 1 - .github/actions/clang-format-lint-action | 1 - .github/actions/clang-tidy-review | 1 - .github/workflows/clang-format.yml | 20 ++++++++++++-- .github/workflows/code-checks.yml | 33 ++++++++++++++++++------ .github/workflows/license-eyes.yml | 3 --- .gitmodules | 9 ------- 7 files changed, 43 insertions(+), 25 deletions(-) delete mode 160000 .github/actions/action-sh-checker delete mode 160000 .github/actions/clang-format-lint-action delete mode 160000 .github/actions/clang-tidy-review diff --git a/.github/actions/action-sh-checker b/.github/actions/action-sh-checker deleted file mode 160000 index 76ab0b22e1f194..00000000000000 --- a/.github/actions/action-sh-checker +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 76ab0b22e1f194e4a582edc7969df6485c4e9246 diff --git a/.github/actions/clang-format-lint-action b/.github/actions/clang-format-lint-action deleted file mode 160000 index 6adbe14579e5b8..00000000000000 --- a/.github/actions/clang-format-lint-action +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6adbe14579e5b8e19eb3e31e5ff2479f3bd302c7 diff --git a/.github/actions/clang-tidy-review b/.github/actions/clang-tidy-review deleted file mode 160000 index 2c55ef8cfc9acb..00000000000000 --- a/.github/actions/clang-tidy-review +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2c55ef8cfc9acb3715d433e58aea086dcec9b206 diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml index f69cb953683895..c804b753a3bbc4 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -31,14 +31,21 @@ jobs: uses: actions/checkout@v3 with: persist-credentials: false - submodules: recursive - name: Checkout ${{ github.ref }} ( ${{ github.event.pull_request.head.sha }} ) if: ${{ github.event_name == 'pull_request_target' }} uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - submodules: recursive + + - name: Checkout paths-filter + run: | + rm -rf ./.github/actions/paths-filter + git clone https://github.com/dorny/paths-filter .github/actions/paths-filter + + pushd .github/actions/paths-filter &>/dev/null + git checkout 4512585405083f25c027a35db413c2b3b9006d50 + popd &>/dev/null - name: Paths filter uses: ./.github/actions/paths-filter @@ -49,6 +56,15 @@ jobs: - 'be/src/**' - 'be/test/**' + - name: Checkout clang-format-lint-action + run: | + rm -rf ./.github/actions/clang-format-lint-action + git clone https://github.com/DoozyX/clang-format-lint-action .github/actions/clang-format-lint-action + + pushd .github/actions/clang-format-lint-action &>/dev/null + git checkout 6adbe14579e5b8e19eb3e31e5ff2479f3bd302c7 + popd &>/dev/null + - name: "Format it!" if: ${{ steps.filter.outputs.be_changes == 'true' }} uses: ./.github/actions/clang-format-lint-action diff --git a/.github/workflows/code-checks.yml b/.github/workflows/code-checks.yml index 652aa7f81ea861..9e314bfb6dfc25 100644 --- a/.github/workflows/code-checks.yml +++ b/.github/workflows/code-checks.yml @@ -27,21 +27,22 @@ jobs: - name: Checkout ${{ github.ref }} ( ${{ github.sha }} ) if: ${{ github.event_name != 'pull_request_target' }} uses: actions/checkout@v3 - with: - submodules: recursive - name: Checkout ${{ github.ref }} ( ${{ github.event.pull_request.head.sha }} ) if: ${{ github.event_name == 'pull_request_target' }} uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - submodules: recursive - - name: Patch + - name: Checkout action-sh-checker run: | - pushd .github/actions/action-sh-checker >/dev/null + rm -rf ./.github/actions/action-sh-checker + git clone https://github.com/luizm/action-sh-checker .github/actions/action-sh-checker + + pushd .github/actions/action-sh-checker &>/dev/null + git checkout 76ab0b22e1f194e4a582edc7969df6485c4e9246 sed -i 's/\[ "$GITHUB_EVENT_NAME" == "pull_request" \]/\[\[ "$GITHUB_EVENT_NAME" == "pull_request" || "$GITHUB_EVENT_NAME" == "pull_request_target" \]\]/' entrypoint.sh - popd >/dev/null + popd &>/dev/null - name: Run ShellCheck uses: ./.github/actions/action-sh-checker @@ -63,7 +64,15 @@ jobs: uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - submodules: recursive + + - name: Checkout paths-filter + run: | + rm -rf ./.github/actions/paths-filter + git clone https://github.com/dorny/paths-filter .github/actions/paths-filter + + pushd .github/actions/paths-filter &>/dev/null + git checkout 4512585405083f25c027a35db413c2b3b9006d50 + popd &>/dev/null - name: Paths Filter uses: ./.github/actions/paths-filter @@ -117,7 +126,6 @@ jobs: uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - submodules: recursive - name: Download uses: actions/download-artifact@v3 @@ -125,6 +133,15 @@ jobs: name: compile_commands path: ./be/build_Release + - name: Checkout clang-tidy review + run: | + rm -rf ./.github/actions/clang-tidy-review + git clone https://github.com/ZedThree/clang-tidy-review .github/actions/clang-tidy-review + + pushd .github/actions/clang-tidy-review &>/dev/null + git checkout 2c55ef8cfc9acb3715d433e58aea086dcec9b206 + popd &>/dev/null + - name: Run clang-tidy review uses: ./.github/actions/clang-tidy-review id: review diff --git a/.github/workflows/license-eyes.yml b/.github/workflows/license-eyes.yml index 823ac845b3b0c1..890efb2d9d1196 100644 --- a/.github/workflows/license-eyes.yml +++ b/.github/workflows/license-eyes.yml @@ -30,15 +30,12 @@ jobs: - name: "Checkout ${{ github.ref }} ( ${{ github.sha }} )" if: ${{ github.event_name != 'pull_request_target' }} uses: actions/checkout@v3 - with: - submodules: recursive - name: Checkout ${{ github.ref }} ( ${{ github.event.pull_request.head.sha }} ) if: ${{ github.event_name == 'pull_request_target' }} uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} - submodules: recursive - name: Check License uses: apache/skywalking-eyes@v0.2.0 diff --git a/.gitmodules b/.gitmodules index 9fe51bfd1d056d..a4e579b1794833 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,9 +4,6 @@ [submodule ".github/actions/get-workflow-origin"] path = .github/actions/get-workflow-origin url = https://github.com/potiuk/get-workflow-origin.git -[submodule ".github/actions/clang-format-lint-action"] - path = .github/actions/clang-format-lint-action - url = https://github.com/DoozyX/clang-format-lint-action.git [submodule ".github/actions/setup-maven"] path = .github/actions/setup-maven url = https://github.com/stCarolas/setup-maven.git @@ -19,12 +16,6 @@ [submodule ".github/actions/ccache-action"] path = .github/actions/ccache-action url = https://github.com/hendrikmuhs/ccache-action -[submodule ".github/actions/action-sh-checker"] - path = .github/actions/action-sh-checker - url = https://github.com/luizm/action-sh-checker -[submodule ".github/actions/clang-tidy-review"] - path = .github/actions/clang-tidy-review - url = https://github.com/ZedThree/clang-tidy-review.git [submodule "be/src/apache-orc"] path = be/src/apache-orc url = https://github.com/apache/doris-thirdparty.git From 7bad2e1d9fa3f8cab1584a7248fcc4c466b37714 Mon Sep 17 00:00:00 2001 From: seawinde <149132972+seawinde@users.noreply.github.com> Date: Wed, 8 Nov 2023 11:28:48 +0800 Subject: [PATCH 34/88] [opt](nereids) infer result column name in ctas and query stmt (#26055) Infer name if it is an expression and doesn't alias artificially when create or select stmt in nereids. The infer name strategy is the same as #24990 --- .../org/apache/doris/analysis/SelectStmt.java | 8 +- .../nereids/analyzer/UnboundFunction.java | 2 +- .../rules/analysis/BindExpression.java | 17 +- .../expressions/AggregateExpression.java | 2 +- .../nereids/trees/expressions/Alias.java | 4 + .../expressions/AssertNumRowsElement.java | 2 +- .../nereids/trees/expressions/Expression.java | 2 +- .../trees/expressions/NamedExpression.java | 2 +- .../trees/expressions/SubqueryExpr.java | 2 +- .../expressions/functions/BoundFunction.java | 2 +- .../trees/expressions/literal/Literal.java | 2 +- .../plans/visitor/InferPlanOutputAlias.java | 76 ++ .../apache/doris/qe/OlapQueryCacheTest.java | 22 +- .../nereids_p0/infer_expr_name/load.groovy | 821 ++++++++++++++++++ .../nereids_p0/infer_expr_name/query13.groovy | 81 ++ .../nereids_p0/infer_expr_name/query14.groovy | 137 +++ .../nereids_p0/infer_expr_name/query15.groovy | 49 ++ .../nereids_p0/infer_expr_name/query2.groovy | 94 ++ .../nereids_p0/infer_expr_name/query23.groovy | 80 ++ .../nereids_p0/infer_expr_name/query35.groovy | 102 +++ .../nereids_p0/infer_expr_name/query38.groovy | 51 ++ .../nereids_p0/infer_expr_name/query41.groovy | 80 ++ .../nereids_p0/infer_expr_name/query42.groovy | 53 ++ .../nereids_p0/infer_expr_name/query45.groovy | 50 ++ .../nereids_p0/infer_expr_name/query59.groovy | 81 ++ .../nereids_p0/infer_expr_name/query61.groovy | 74 ++ .../nereids_p0/infer_expr_name/query62.groovy | 63 ++ .../nereids_p0/infer_expr_name/query8.groovy | 136 +++ .../nereids_p0/infer_expr_name/query85.groovy | 115 +++ 29 files changed, 2181 insertions(+), 29 deletions(-) create mode 100644 fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/InferPlanOutputAlias.java create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/load.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query13.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query14.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query15.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query2.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query23.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query35.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query38.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query41.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query42.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query45.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query59.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query61.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query62.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query8.groovy create mode 100644 regression-test/suites/nereids_p0/infer_expr_name/query85.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java index 48fd213e4c7832..a9811cf4e02e4e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SelectStmt.java @@ -554,12 +554,8 @@ public void analyze(Analyzer analyzer) throws UserException { } resultExprs.add(rewriteQueryExprByMvColumnExpr(item.getExpr(), analyzer)); String columnLabel = null; - Class statementClazz = analyzer.getRootStatementClazz(); - if (statementClazz != null - && (!QueryStmt.class.isAssignableFrom(statementClazz) || hasOutFileClause())) { - // Infer column name when item is expr - columnLabel = item.toColumnLabel(i); - } + // Infer column name when item is expr, both query and ddl + columnLabel = item.toColumnLabel(i); if (columnLabel == null) { // column label without position is applicative for query and do not infer // column name when item is expr diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundFunction.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundFunction.java index c5cb960dbe5f9d..d73474906a9dd7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundFunction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundFunction.java @@ -62,7 +62,7 @@ public String getName() { } @Override - protected String getExpressionName() { + public String getExpressionName() { return Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java index b2b4c30b9342fc..0d36ca31c32d79 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/analysis/BindExpression.java @@ -37,6 +37,7 @@ import org.apache.doris.nereids.trees.expressions.Alias; import org.apache.doris.nereids.trees.expressions.BoundStar; import org.apache.doris.nereids.trees.expressions.EqualTo; +import org.apache.doris.nereids.trees.expressions.ExprId; import org.apache.doris.nereids.trees.expressions.Expression; import org.apache.doris.nereids.trees.expressions.NamedExpression; import org.apache.doris.nereids.trees.expressions.Properties; @@ -72,12 +73,14 @@ import org.apache.doris.nereids.trees.plans.logical.LogicalSubQueryAlias; import org.apache.doris.nereids.trees.plans.logical.LogicalTVFRelation; import org.apache.doris.nereids.trees.plans.logical.UsingJoin; +import org.apache.doris.nereids.trees.plans.visitor.InferPlanOutputAlias; import org.apache.doris.nereids.util.TypeCoercionUtils; import org.apache.doris.qe.ConnectContext; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableList.Builder; +import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import org.apache.commons.lang3.StringUtils; @@ -564,10 +567,16 @@ protected boolean condition(Rule rule, Plan plan) { ), RuleType.BINDING_RESULT_SINK.build( unboundResultSink().then(sink -> { - List outputExprs = sink.child().getOutput().stream() - .map(NamedExpression.class::cast) - .collect(ImmutableList.toImmutableList()); - return new LogicalResultSink<>(outputExprs, sink.child()); + + final ImmutableListMultimap.Builder exprIdToIndexMapBuilder = + ImmutableListMultimap.builder(); + List childOutput = sink.child().getOutput(); + for (int index = 0; index < childOutput.size(); index++) { + exprIdToIndexMapBuilder.put(childOutput.get(index).getExprId(), index); + } + InferPlanOutputAlias aliasInfer = new InferPlanOutputAlias(childOutput); + sink.child().accept(aliasInfer, exprIdToIndexMapBuilder.build()); + return new LogicalResultSink<>(aliasInfer.getOutputs(), sink.child()); }) ) ).stream().map(ruleCondition).collect(ImmutableList.toImmutableList()); diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AggregateExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AggregateExpression.java index 4eb4653ded10d3..d097efd7aed488 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AggregateExpression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AggregateExpression.java @@ -119,7 +119,7 @@ public String toString() { } @Override - protected String getExpressionName() { + public String getExpressionName() { return Utils.normalizeName(function.getName(), DEFAULT_EXPRESSION_NAME); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Alias.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Alias.java index b02c968baba3a4..877f792e5019ed 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Alias.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Alias.java @@ -146,4 +146,8 @@ public Alias withChildren(List children) { public R accept(ExpressionVisitor visitor, C context) { return visitor.visitAlias(this, context); } + + public boolean isNameFromChild() { + return nameFromChild; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AssertNumRowsElement.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AssertNumRowsElement.java index 8744266c86b72e..9b2261e73bcca5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AssertNumRowsElement.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AssertNumRowsElement.java @@ -88,7 +88,7 @@ public String toSql() { } @Override - protected String getExpressionName() { + public String getExpressionName() { return assertion.name().toLowerCase(); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java index 12a3a9768caf7d..2a432aaa80b8c8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java @@ -96,7 +96,7 @@ public Alias alias(String alias) { // Name of expr, this is used by generating column name automatically when there is no // alias - protected String getExpressionName() { + public String getExpressionName() { return this.exprName; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java index 6c2e14191c07aa..2854704b9223bb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java @@ -58,7 +58,7 @@ public String getQualifiedName() throws UnboundException { } @Override - protected String getExpressionName() { + public String getExpressionName() { return Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java index 6715bed6cc9ed3..d6876873ed3de2 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java @@ -85,7 +85,7 @@ public String toSql() { } @Override - protected String getExpressionName() { + public String getExpressionName() { return "subquery"; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BoundFunction.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BoundFunction.java index d5008748482c5f..e3970161c7567a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BoundFunction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BoundFunction.java @@ -56,7 +56,7 @@ public String getName() { } @Override - protected String getExpressionName() { + public String getExpressionName() { return Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java index e716d66994c69a..c83061f19596fd 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java @@ -132,7 +132,7 @@ public String toSql() { } @Override - protected String getExpressionName() { + public String getExpressionName() { return "literal"; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/InferPlanOutputAlias.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/InferPlanOutputAlias.java new file mode 100644 index 00000000000000..48248e1c5880aa --- /dev/null +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/visitor/InferPlanOutputAlias.java @@ -0,0 +1,76 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.nereids.trees.plans.visitor; + +import org.apache.doris.nereids.trees.expressions.Alias; +import org.apache.doris.nereids.trees.expressions.ExprId; +import org.apache.doris.nereids.trees.expressions.NamedExpression; +import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.Plan; + +import com.google.common.collect.ImmutableCollection; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Infer output column name when it refers an expression and not has an alias manually. + */ +public class InferPlanOutputAlias extends DefaultPlanVisitor> { + + private final List currentOutputs; + private final List finalOutputs; + + public InferPlanOutputAlias(List currentOutputs) { + this.currentOutputs = currentOutputs; + this.finalOutputs = new ArrayList<>(currentOutputs); + } + + @Override + public Void visit(Plan plan, ImmutableMultimap currentExprIdAndIndexMap) { + + List aliasProjects = plan.getExpressions().stream() + .filter(expression -> expression instanceof Alias) + .map(Alias.class::cast) + .collect(Collectors.toList()); + + ImmutableSet currentOutputExprIdSet = currentExprIdAndIndexMap.keySet(); + for (Alias projectItem : aliasProjects) { + ExprId exprId = projectItem.getExprId(); + // Infer name when alias child is expression and alias's name is from child + if (currentOutputExprIdSet.contains(projectItem.getExprId()) + && projectItem.isNameFromChild()) { + String inferredAliasName = projectItem.child().getExpressionName(); + ImmutableCollection outPutExprIndexes = currentExprIdAndIndexMap.get(exprId); + // replace output name by inferred name + outPutExprIndexes.forEach(index -> { + Slot slot = currentOutputs.get(index); + finalOutputs.set(index, slot.withName("__" + inferredAliasName + "_" + index)); + }); + } + } + return super.visit(plan, currentExprIdAndIndexMap); + } + + public List getOutputs() { + return finalOutputs; + } +} diff --git a/fe/fe-core/src/test/java/org/apache/doris/qe/OlapQueryCacheTest.java b/fe/fe-core/src/test/java/org/apache/doris/qe/OlapQueryCacheTest.java index 5e2d13003f2da5..29201d0871150d 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/qe/OlapQueryCacheTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/qe/OlapQueryCacheTest.java @@ -1044,10 +1044,10 @@ public void testSubSelect() throws Exception { cache.rewriteSelectStmt(null); LOG.warn("Sub nokey={}", cache.getNokeyStmt().toSql()); Assert.assertEquals(cache.getNokeyStmt().toSql(), - "SELECT `eventdate` AS `eventdate`, sum(`pv`) AS `sum(``pv``)` FROM (" - + "SELECT `eventdate` AS `eventdate`, count(`userid`) AS `pv` FROM " - + "`testCluster:testDb`.`appevent` WHERE `eventid` = 1" - + " GROUP BY `eventdate`) tbl GROUP BY `eventdate`"); + "SELECT `eventdate` AS `eventdate`, sum(`pv`) AS `__sum_1` " + + "FROM (SELECT `eventdate` AS `eventdate`, count(`userid`) AS `pv` " + + "FROM `testCluster:testDb`.`appevent` WHERE `eventid` = 1 " + + "GROUP BY `eventdate`) tbl GROUP BY `eventdate`"); PartitionRange range = cache.getPartitionRange(); boolean flag = range.analytics(); @@ -1066,11 +1066,11 @@ public void testSubSelect() throws Exception { sql = ca.getRewriteStmt().toSql(); LOG.warn("Sub rewrite={}", sql); Assert.assertEquals(sql, - "SELECT `eventdate` AS `eventdate`, sum(`pv`) AS `sum(``pv``)` FROM (" - + "SELECT `eventdate` AS `eventdate`, count(`userid`) AS `pv` FROM " - + "`testCluster:testDb`.`appevent` WHERE " - + "`eventdate` > '2020-01-13' AND `eventdate` < '2020-01-16' AND `eventid` = 1 GROUP BY " - + "`eventdate`) tbl GROUP BY `eventdate`"); + "SELECT `eventdate` AS `eventdate`, sum(`pv`) AS `__sum_1` " + + "FROM (SELECT `eventdate` AS `eventdate`, count(`userid`) AS `pv` " + + "FROM `testCluster:testDb`.`appevent` WHERE `eventdate` > '2020-01-13' " + + "AND `eventdate` < '2020-01-16' AND `eventid` = 1 " + + "GROUP BY `eventdate`) tbl GROUP BY `eventdate`"); } catch (Exception e) { LOG.warn("sub ex={}", e); Assert.fail(e.getMessage()); @@ -1122,8 +1122,8 @@ public void testSqlCacheKey() { SqlCache sqlCache = (SqlCache) ca.getCache(); String cacheKey = sqlCache.getSqlWithViewStmt(); - Assert.assertEquals(cacheKey, "SELECT `eventdate` AS `eventdate`, count(`userid`) AS " - + "`count(``userid``)` FROM `testCluster:testDb`.`appevent` WHERE `eventdate` >= '2020-01-12' AND " + Assert.assertEquals(cacheKey, "SELECT `eventdate` AS `eventdate`, count(`userid`) " + + "AS `__count_1` FROM `testCluster:testDb`.`appevent` WHERE `eventdate` >= '2020-01-12' AND " + "`eventdate` <= '2020-01-14' GROUP BY `eventdate`|"); Assert.assertEquals(selectedPartitionIds.size(), sqlCache.getSumOfPartitionNum()); } diff --git a/regression-test/suites/nereids_p0/infer_expr_name/load.groovy b/regression-test/suites/nereids_p0/infer_expr_name/load.groovy new file mode 100644 index 00000000000000..ecc84655e05ff2 --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/load.groovy @@ -0,0 +1,821 @@ +package infer_expr_name +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("load") { + String database = context.config.getDbNameByFile(context.file) + sql "drop database if exists ${database}" + sql "create database ${database}" + sql "use ${database}" + + sql ''' + drop table if exists customer_demographics + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS customer_demographics ( + cd_demo_sk bigint not null, + cd_gender char(1), + cd_marital_status char(1), + cd_education_status char(20), + cd_purchase_estimate integer, + cd_credit_rating char(10), + cd_dep_count integer, + cd_dep_employed_count integer, + cd_dep_college_count integer + ) + DUPLICATE KEY(cd_demo_sk) + DISTRIBUTED BY HASH(cd_gender) BUCKETS 12 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists reason + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS reason ( + r_reason_sk bigint not null, + r_reason_id char(16) not null, + r_reason_desc char(100) + ) + DUPLICATE KEY(r_reason_sk) + DISTRIBUTED BY HASH(r_reason_sk) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists date_dim + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS date_dim ( + d_date_sk bigint not null, + d_date_id char(16) not null, + d_date datev2, + d_month_seq integer, + d_week_seq integer, + d_quarter_seq integer, + d_year integer, + d_dow integer, + d_moy integer, + d_dom integer, + d_qoy integer, + d_fy_year integer, + d_fy_quarter_seq integer, + d_fy_week_seq integer, + d_day_name char(9), + d_quarter_name char(6), + d_holiday char(1), + d_weekend char(1), + d_following_holiday char(1), + d_first_dom integer, + d_last_dom integer, + d_same_day_ly integer, + d_same_day_lq integer, + d_current_day char(1), + d_current_week char(1), + d_current_month char(1), + d_current_quarter char(1), + d_current_year char(1) + ) + DUPLICATE KEY(d_date_sk) + PARTITION BY RANGE(d_date_sk) + ( + PARTITION `ppast` values less than("2450815"), + PARTITION `p1998` values less than("2451180"), + PARTITION `p1999` values less than("2451545"), + PARTITION `p2000` values less than("2451911"), + PARTITION `p2001` values less than("2452276"), + PARTITION `p2002` values less than("2452641"), + PARTITION `p2003` values less than("2453006"), + PARTITION `pfuture` values less than("9999999") + ) + DISTRIBUTED BY HASH(d_date_sk) BUCKETS 12 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists warehouse + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS warehouse ( + w_warehouse_sk bigint not null, + w_warehouse_id char(16) not null, + w_warehouse_name varchar(20), + w_warehouse_sq_ft integer, + w_street_number char(10), + w_street_name varchar(60), + w_street_type char(15), + w_suite_number char(10), + w_city varchar(60), + w_county varchar(30), + w_state char(2), + w_zip char(10), + w_country varchar(20), + w_gmt_offset decimalv3(5,2) + ) + DUPLICATE KEY(w_warehouse_sk) + DISTRIBUTED BY HASH(w_warehouse_sk) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists catalog_sales + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS catalog_sales ( + cs_sold_date_sk bigint, + cs_item_sk bigint not null, + cs_order_number bigint not null, + cs_sold_time_sk bigint, + cs_ship_date_sk bigint, + cs_bill_customer_sk bigint, + cs_bill_cdemo_sk bigint, + cs_bill_hdemo_sk bigint, + cs_bill_addr_sk bigint, + cs_ship_customer_sk bigint, + cs_ship_cdemo_sk bigint, + cs_ship_hdemo_sk bigint, + cs_ship_addr_sk bigint, + cs_call_center_sk bigint, + cs_catalog_page_sk bigint, + cs_ship_mode_sk bigint, + cs_warehouse_sk bigint, + cs_promo_sk bigint, + cs_quantity integer, + cs_wholesale_cost decimalv3(7,2), + cs_list_price decimalv3(7,2), + cs_sales_price decimalv3(7,2), + cs_ext_discount_amt decimalv3(7,2), + cs_ext_sales_price decimalv3(7,2), + cs_ext_wholesale_cost decimalv3(7,2), + cs_ext_list_price decimalv3(7,2), + cs_ext_tax decimalv3(7,2), + cs_coupon_amt decimalv3(7,2), + cs_ext_ship_cost decimalv3(7,2), + cs_net_paid decimalv3(7,2), + cs_net_paid_inc_tax decimalv3(7,2), + cs_net_paid_inc_ship decimalv3(7,2), + cs_net_paid_inc_ship_tax decimalv3(7,2), + cs_net_profit decimalv3(7,2) + ) + DUPLICATE KEY(cs_sold_date_sk, cs_item_sk) + DISTRIBUTED BY HASH(cs_item_sk, cs_order_number) BUCKETS 32 + PROPERTIES ( + "replication_num" = "1", + "colocate_with" = "catalog" + ) + ''' + + sql ''' + drop table if exists call_center + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS call_center ( + cc_call_center_sk bigint not null, + cc_call_center_id char(16) not null, + cc_rec_start_date datev2, + cc_rec_end_date datev2, + cc_closed_date_sk integer, + cc_open_date_sk integer, + cc_name varchar(50), + cc_class varchar(50), + cc_employees integer, + cc_sq_ft integer, + cc_hours char(20), + cc_manager varchar(40), + cc_mkt_id integer, + cc_mkt_class char(50), + cc_mkt_desc varchar(100), + cc_market_manager varchar(40), + cc_division integer, + cc_division_name varchar(50), + cc_company integer, + cc_company_name char(50), + cc_street_number char(10), + cc_street_name varchar(60), + cc_street_type char(15), + cc_suite_number char(10), + cc_city varchar(60), + cc_county varchar(30), + cc_state char(2), + cc_zip char(10), + cc_country varchar(20), + cc_gmt_offset decimalv3(5,2), + cc_tax_percentage decimalv3(5,2) + ) + DUPLICATE KEY(cc_call_center_sk) + DISTRIBUTED BY HASH(cc_call_center_sk) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists inventory + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS inventory ( + inv_date_sk bigint not null, + inv_item_sk bigint not null, + inv_warehouse_sk bigint, + inv_quantity_on_hand integer + ) + DUPLICATE KEY(inv_date_sk, inv_item_sk, inv_warehouse_sk) + DISTRIBUTED BY HASH(inv_date_sk, inv_item_sk, inv_warehouse_sk) BUCKETS 32 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists catalog_returns + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS catalog_returns ( + cr_item_sk bigint not null, + cr_order_number bigint not null, + cr_returned_date_sk bigint, + cr_returned_time_sk bigint, + cr_refunded_customer_sk bigint, + cr_refunded_cdemo_sk bigint, + cr_refunded_hdemo_sk bigint, + cr_refunded_addr_sk bigint, + cr_returning_customer_sk bigint, + cr_returning_cdemo_sk bigint, + cr_returning_hdemo_sk bigint, + cr_returning_addr_sk bigint, + cr_call_center_sk bigint, + cr_catalog_page_sk bigint, + cr_ship_mode_sk bigint, + cr_warehouse_sk bigint, + cr_reason_sk bigint, + cr_return_quantity integer, + cr_return_amount decimalv3(7,2), + cr_return_tax decimalv3(7,2), + cr_return_amt_inc_tax decimalv3(7,2), + cr_fee decimalv3(7,2), + cr_return_ship_cost decimalv3(7,2), + cr_refunded_cash decimalv3(7,2), + cr_reversed_charge decimalv3(7,2), + cr_store_credit decimalv3(7,2), + cr_net_loss decimalv3(7,2) + ) + DUPLICATE KEY(cr_item_sk, cr_order_number) + DISTRIBUTED BY HASH(cr_item_sk, cr_order_number) BUCKETS 32 + PROPERTIES ( + "replication_num" = "1", + "colocate_with" = "catalog" + ) + ''' + + sql ''' + drop table if exists household_demographics + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS household_demographics ( + hd_demo_sk bigint not null, + hd_income_band_sk bigint, + hd_buy_potential char(15), + hd_dep_count integer, + hd_vehicle_count integer + ) + DUPLICATE KEY(hd_demo_sk) + DISTRIBUTED BY HASH(hd_demo_sk) BUCKETS 3 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists customer_address + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS customer_address ( + ca_address_sk bigint not null, + ca_address_id char(16) not null, + ca_street_number char(10), + ca_street_name varchar(60), + ca_street_type char(15), + ca_suite_number char(10), + ca_city varchar(60), + ca_county varchar(30), + ca_state char(2), + ca_zip char(10), + ca_country varchar(20), + ca_gmt_offset decimalv3(5,2), + ca_location_type char(20) + ) + DUPLICATE KEY(ca_address_sk) + DISTRIBUTED BY HASH(ca_address_sk) BUCKETS 12 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists income_band + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS income_band ( + ib_income_band_sk bigint not null, + ib_lower_bound integer, + ib_upper_bound integer + ) + DUPLICATE KEY(ib_income_band_sk) + DISTRIBUTED BY HASH(ib_income_band_sk) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists catalog_page + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS catalog_page ( + cp_catalog_page_sk bigint not null, + cp_catalog_page_id char(16) not null, + cp_start_date_sk integer, + cp_end_date_sk integer, + cp_department varchar(50), + cp_catalog_number integer, + cp_catalog_page_number integer, + cp_description varchar(100), + cp_type varchar(100) + ) + DUPLICATE KEY(cp_catalog_page_sk) + DISTRIBUTED BY HASH(cp_catalog_page_sk) BUCKETS 3 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists item + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS item ( + i_item_sk bigint not null, + i_item_id char(16) not null, + i_rec_start_date datev2, + i_rec_end_date datev2, + i_item_desc varchar(200), + i_current_price decimalv3(7,2), + i_wholesale_cost decimalv3(7,2), + i_brand_id integer, + i_brand char(50), + i_class_id integer, + i_class char(50), + i_category_id integer, + i_category char(50), + i_manufact_id integer, + i_manufact char(50), + i_size char(20), + i_formulation char(20), + i_color char(20), + i_units char(10), + i_container char(10), + i_manager_id integer, + i_product_name char(50) + ) + DUPLICATE KEY(i_item_sk) + DISTRIBUTED BY HASH(i_item_sk) BUCKETS 12 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists web_returns + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS web_returns ( + wr_item_sk bigint not null, + wr_order_number bigint not null, + wr_returned_date_sk bigint, + wr_returned_time_sk bigint, + wr_refunded_customer_sk bigint, + wr_refunded_cdemo_sk bigint, + wr_refunded_hdemo_sk bigint, + wr_refunded_addr_sk bigint, + wr_returning_customer_sk bigint, + wr_returning_cdemo_sk bigint, + wr_returning_hdemo_sk bigint, + wr_returning_addr_sk bigint, + wr_web_page_sk bigint, + wr_reason_sk bigint, + wr_return_quantity integer, + wr_return_amt decimalv3(7,2), + wr_return_tax decimalv3(7,2), + wr_return_amt_inc_tax decimalv3(7,2), + wr_fee decimalv3(7,2), + wr_return_ship_cost decimalv3(7,2), + wr_refunded_cash decimalv3(7,2), + wr_reversed_charge decimalv3(7,2), + wr_account_credit decimalv3(7,2), + wr_net_loss decimalv3(7,2) + ) + DUPLICATE KEY(wr_item_sk, wr_order_number) + DISTRIBUTED BY HASH(wr_item_sk, wr_order_number) BUCKETS 32 + PROPERTIES ( + "replication_num" = "1", + "colocate_with" = "web" + ) + ''' + + sql ''' + drop table if exists web_site + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS web_site ( + web_site_sk bigint not null, + web_site_id char(16) not null, + web_rec_start_date datev2, + web_rec_end_date datev2, + web_name varchar(50), + web_open_date_sk bigint, + web_close_date_sk bigint, + web_class varchar(50), + web_manager varchar(40), + web_mkt_id integer, + web_mkt_class varchar(50), + web_mkt_desc varchar(100), + web_market_manager varchar(40), + web_company_id integer, + web_company_name char(50), + web_street_number char(10), + web_street_name varchar(60), + web_street_type char(15), + web_suite_number char(10), + web_city varchar(60), + web_county varchar(30), + web_state char(2), + web_zip char(10), + web_country varchar(20), + web_gmt_offset decimalv3(5,2), + web_tax_percentage decimalv3(5,2) + ) + DUPLICATE KEY(web_site_sk) + DISTRIBUTED BY HASH(web_site_sk) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists promotion + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS promotion ( + p_promo_sk bigint not null, + p_promo_id char(16) not null, + p_start_date_sk bigint, + p_end_date_sk bigint, + p_item_sk bigint, + p_cost decimalv3(15,2), + p_response_targe integer, + p_promo_name char(50), + p_channel_dmail char(1), + p_channel_email char(1), + p_channel_catalog char(1), + p_channel_tv char(1), + p_channel_radio char(1), + p_channel_press char(1), + p_channel_event char(1), + p_channel_demo char(1), + p_channel_details varchar(100), + p_purpose char(15), + p_discount_active char(1) + ) + DUPLICATE KEY(p_promo_sk) + DISTRIBUTED BY HASH(p_promo_sk) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists web_sales + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS web_sales ( + ws_sold_date_sk bigint, + ws_item_sk bigint not null, + ws_order_number bigint not null, + ws_sold_time_sk bigint, + ws_ship_date_sk bigint, + ws_bill_customer_sk bigint, + ws_bill_cdemo_sk bigint, + ws_bill_hdemo_sk bigint, + ws_bill_addr_sk bigint, + ws_ship_customer_sk bigint, + ws_ship_cdemo_sk bigint, + ws_ship_hdemo_sk bigint, + ws_ship_addr_sk bigint, + ws_web_page_sk bigint, + ws_web_site_sk bigint, + ws_ship_mode_sk bigint, + ws_warehouse_sk bigint, + ws_promo_sk bigint, + ws_quantity integer, + ws_wholesale_cost decimalv3(7,2), + ws_list_price decimalv3(7,2), + ws_sales_price decimalv3(7,2), + ws_ext_discount_amt decimalv3(7,2), + ws_ext_sales_price decimalv3(7,2), + ws_ext_wholesale_cost decimalv3(7,2), + ws_ext_list_price decimalv3(7,2), + ws_ext_tax decimalv3(7,2), + ws_coupon_amt decimalv3(7,2), + ws_ext_ship_cost decimalv3(7,2), + ws_net_paid decimalv3(7,2), + ws_net_paid_inc_tax decimalv3(7,2), + ws_net_paid_inc_ship decimalv3(7,2), + ws_net_paid_inc_ship_tax decimalv3(7,2), + ws_net_profit decimalv3(7,2) + ) + DUPLICATE KEY(ws_sold_date_sk, ws_item_sk) + DISTRIBUTED BY HASH(ws_item_sk, ws_order_number) BUCKETS 32 + PROPERTIES ( + "replication_num" = "1", + "colocate_with" = "web" + ) + ''' + + sql ''' + drop table if exists store + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS store ( + s_store_sk bigint not null, + s_store_id char(16) not null, + s_rec_start_date datev2, + s_rec_end_date datev2, + s_closed_date_sk bigint, + s_store_name varchar(50), + s_number_employees integer, + s_floor_space integer, + s_hours char(20), + s_manager varchar(40), + s_market_id integer, + s_geography_class varchar(100), + s_market_desc varchar(100), + s_market_manager varchar(40), + s_division_id integer, + s_division_name varchar(50), + s_company_id integer, + s_company_name varchar(50), + s_street_number varchar(10), + s_street_name varchar(60), + s_street_type char(15), + s_suite_number char(10), + s_city varchar(60), + s_county varchar(30), + s_state char(2), + s_zip char(10), + s_country varchar(20), + s_gmt_offset decimalv3(5,2), + s_tax_precentage decimalv3(5,2) + ) + DUPLICATE KEY(s_store_sk) + DISTRIBUTED BY HASH(s_store_sk) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists time_dim + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS time_dim ( + t_time_sk bigint not null, + t_time_id char(16) not null, + t_time integer, + t_hour integer, + t_minute integer, + t_second integer, + t_am_pm char(2), + t_shift char(20), + t_sub_shift char(20), + t_meal_time char(20) + ) + DUPLICATE KEY(t_time_sk) + DISTRIBUTED BY HASH(t_time_sk) BUCKETS 12 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists web_page + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS web_page ( + wp_web_page_sk bigint not null, + wp_web_page_id char(16) not null, + wp_rec_start_date datev2, + wp_rec_end_date datev2, + wp_creation_date_sk bigint, + wp_access_date_sk bigint, + wp_autogen_flag char(1), + wp_customer_sk bigint, + wp_url varchar(100), + wp_type char(50), + wp_char_count integer, + wp_link_count integer, + wp_image_count integer, + wp_max_ad_count integer + ) + DUPLICATE KEY(wp_web_page_sk) + DISTRIBUTED BY HASH(wp_web_page_sk) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists store_returns + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS store_returns ( + sr_item_sk bigint not null, + sr_ticket_number bigint not null, + sr_returned_date_sk bigint, + sr_return_time_sk bigint, + sr_customer_sk bigint, + sr_cdemo_sk bigint, + sr_hdemo_sk bigint, + sr_addr_sk bigint, + sr_store_sk bigint, + sr_reason_sk bigint, + sr_return_quantity integer, + sr_return_amt decimalv3(7,2), + sr_return_tax decimalv3(7,2), + sr_return_amt_inc_tax decimalv3(7,2), + sr_fee decimalv3(7,2), + sr_return_ship_cost decimalv3(7,2), + sr_refunded_cash decimalv3(7,2), + sr_reversed_charge decimalv3(7,2), + sr_store_credit decimalv3(7,2), + sr_net_loss decimalv3(7,2) + ) + duplicate key(sr_item_sk, sr_ticket_number) + distributed by hash (sr_item_sk, sr_ticket_number) buckets 32 + properties ( + "replication_num" = "1", + "colocate_with" = "store" + ) + ''' + + sql ''' + drop table if exists store_sales + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS store_sales ( + ss_sold_date_sk bigint, + ss_item_sk bigint not null, + ss_ticket_number bigint not null, + ss_sold_time_sk bigint, + ss_customer_sk bigint, + ss_cdemo_sk bigint, + ss_hdemo_sk bigint, + ss_addr_sk bigint, + ss_store_sk bigint, + ss_promo_sk bigint, + ss_quantity integer, + ss_wholesale_cost decimalv3(7,2), + ss_list_price decimalv3(7,2), + ss_sales_price decimalv3(7,2), + ss_ext_discount_amt decimalv3(7,2), + ss_ext_sales_price decimalv3(7,2), + ss_ext_wholesale_cost decimalv3(7,2), + ss_ext_list_price decimalv3(7,2), + ss_ext_tax decimalv3(7,2), + ss_coupon_amt decimalv3(7,2), + ss_net_paid decimalv3(7,2), + ss_net_paid_inc_tax decimalv3(7,2), + ss_net_profit decimalv3(7,2) + ) + DUPLICATE KEY(ss_sold_date_sk, ss_item_sk) + DISTRIBUTED BY HASH(ss_item_sk, ss_ticket_number) BUCKETS 32 + PROPERTIES ( + "replication_num" = "1", + "colocate_with" = "store" + ) + ''' + + sql ''' + drop table if exists ship_mode + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS ship_mode ( + sm_ship_mode_sk bigint not null, + sm_ship_mode_id char(16) not null, + sm_type char(30), + sm_code char(10), + sm_carrier char(20), + sm_contract char(20) + ) + DUPLICATE KEY(sm_ship_mode_sk) + DISTRIBUTED BY HASH(sm_ship_mode_sk) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists customer + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS customer ( + c_customer_sk bigint not null, + c_customer_id char(16) not null, + c_current_cdemo_sk bigint, + c_current_hdemo_sk bigint, + c_current_addr_sk bigint, + c_first_shipto_date_sk bigint, + c_first_sales_date_sk bigint, + c_salutation char(10), + c_first_name char(20), + c_last_name char(30), + c_preferred_cust_flag char(1), + c_birth_day integer, + c_birth_month integer, + c_birth_year integer, + c_birth_country varchar(20), + c_login char(13), + c_email_address char(50), + c_last_review_date_sk bigint + ) + DUPLICATE KEY(c_customer_sk) + DISTRIBUTED BY HASH(c_customer_id) BUCKETS 12 + PROPERTIES ( + "replication_num" = "1" + ) + ''' + + sql ''' + drop table if exists dbgen_version + ''' + + sql ''' + CREATE TABLE IF NOT EXISTS dbgen_version + ( + dv_version varchar(16) , + dv_create_date datev2 , + dv_create_time datetime , + dv_cmdline_args varchar(200) + ) + DUPLICATE KEY(dv_version) + DISTRIBUTED BY HASH(dv_version) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1" + ) + ''' +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query13.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query13.groovy new file mode 100644 index 00000000000000..f0a44ffff43ef3 --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query13.groovy @@ -0,0 +1,81 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +select avg(ss_quantity) + ,avg(ss_ext_sales_price) + ,avg(ss_ext_wholesale_cost) + ,sum(ss_ext_wholesale_cost) + from store_sales + ,store + ,customer_demographics + ,household_demographics + ,customer_address + ,date_dim + where s_store_sk = ss_store_sk + and ss_sold_date_sk = d_date_sk and d_year = 2001 + and((ss_hdemo_sk=hd_demo_sk + and cd_demo_sk = ss_cdemo_sk + and cd_marital_status = 'D' + and cd_education_status = 'Unknown' + and ss_sales_price between 100.00 and 150.00 + and hd_dep_count = 3 + )or + (ss_hdemo_sk=hd_demo_sk + and cd_demo_sk = ss_cdemo_sk + and cd_marital_status = 'S' + and cd_education_status = 'College' + and ss_sales_price between 50.00 and 100.00 + and hd_dep_count = 1 + ) or + (ss_hdemo_sk=hd_demo_sk + and cd_demo_sk = ss_cdemo_sk + and cd_marital_status = 'M' + and cd_education_status = '4 yr Degree' + and ss_sales_price between 150.00 and 200.00 + and hd_dep_count = 1 + )) + and((ss_addr_sk = ca_address_sk + and ca_country = 'United States' + and ca_state in ('SD', 'KS', 'MI') + and ss_net_profit between 100 and 200 + ) or + (ss_addr_sk = ca_address_sk + and ca_country = 'United States' + and ca_state in ('MO', 'ND', 'CO') + and ss_net_profit between 150 and 300 + ) or + (ss_addr_sk = ca_address_sk + and ca_country = 'United States' + and ca_state in ('NH', 'OH', 'TX') + and ss_net_profit between 50 and 250 + ));""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("__avg_0")) + assertTrue(topPlan.contains("__avg_1")) + assertTrue(topPlan.contains("__avg_2")) + assertTrue(topPlan.contains("__sum_3")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query14.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query14.groovy new file mode 100644 index 00000000000000..6218108d388216 --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query14.groovy @@ -0,0 +1,137 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +with cross_items as + (select i_item_sk ss_item_sk + from item, + (select iss.i_brand_id brand_id + ,iss.i_class_id class_id + ,iss.i_category_id category_id + from store_sales + ,item iss + ,date_dim d1 + where ss_item_sk = iss.i_item_sk + and ss_sold_date_sk = d1.d_date_sk + and d1.d_year between 2000 AND 2000 + 2 + intersect + select ics.i_brand_id + ,ics.i_class_id + ,ics.i_category_id + from catalog_sales + ,item ics + ,date_dim d2 + where cs_item_sk = ics.i_item_sk + and cs_sold_date_sk = d2.d_date_sk + and d2.d_year between 2000 AND 2000 + 2 + intersect + select iws.i_brand_id + ,iws.i_class_id + ,iws.i_category_id + from web_sales + ,item iws + ,date_dim d3 + where ws_item_sk = iws.i_item_sk + and ws_sold_date_sk = d3.d_date_sk + and d3.d_year between 2000 AND 2000 + 2) + t where i_brand_id = brand_id + and i_class_id = class_id + and i_category_id = category_id +), + avg_sales as + (select avg(quantity*list_price) average_sales + from (select ss_quantity quantity + ,ss_list_price list_price + from store_sales + ,date_dim + where ss_sold_date_sk = d_date_sk + and d_year between 2000 and 2000 + 2 + union all + select cs_quantity quantity + ,cs_list_price list_price + from catalog_sales + ,date_dim + where cs_sold_date_sk = d_date_sk + and d_year between 2000 and 2000 + 2 + union all + select ws_quantity quantity + ,ws_list_price list_price + from web_sales + ,date_dim + where ws_sold_date_sk = d_date_sk + and d_year between 2000 and 2000 + 2) x) + select channel, i_brand_id,i_class_id,i_category_id,sum(sales), sum(number_sales) + from( + select 'store' channel, i_brand_id,i_class_id + ,i_category_id,sum(ss_quantity*ss_list_price) sales + , count(*) number_sales + from store_sales + ,item + ,date_dim + where ss_item_sk in (select ss_item_sk from cross_items) + and ss_item_sk = i_item_sk + and ss_sold_date_sk = d_date_sk + and d_year = 2000+2 + and d_moy = 11 + group by i_brand_id,i_class_id,i_category_id + having sum(ss_quantity*ss_list_price) > (select average_sales from avg_sales) + union all + select 'catalog' channel, i_brand_id,i_class_id,i_category_id, sum(cs_quantity*cs_list_price) sales, count(*) number_sales + from catalog_sales + ,item + ,date_dim + where cs_item_sk in (select ss_item_sk from cross_items) + and cs_item_sk = i_item_sk + and cs_sold_date_sk = d_date_sk + and d_year = 2000+2 + and d_moy = 11 + group by i_brand_id,i_class_id,i_category_id + having sum(cs_quantity*cs_list_price) > (select average_sales from avg_sales) + union all + select 'web' channel, i_brand_id,i_class_id,i_category_id, sum(ws_quantity*ws_list_price) sales , count(*) number_sales + from web_sales + ,item + ,date_dim + where ws_item_sk in (select ss_item_sk from cross_items) + and ws_item_sk = i_item_sk + and ws_sold_date_sk = d_date_sk + and d_year = 2000+2 + and d_moy = 11 + group by i_brand_id,i_class_id,i_category_id + having sum(ws_quantity*ws_list_price) > (select average_sales from avg_sales) + ) y + group by rollup (channel, i_brand_id,i_class_id,i_category_id) + order by channel,i_brand_id,i_class_id,i_category_id + limit 100; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("channel")) + assertTrue(topPlan.contains("i_brand_id")) + assertTrue(topPlan.contains("i_class_id")) + assertTrue(topPlan.contains("i_category_id")) + assertTrue(topPlan.contains("__sum_4")) + assertTrue(topPlan.contains("__sum_5")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query15.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query15.groovy new file mode 100644 index 00000000000000..f7b87dc8e8e9b4 --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query15.groovy @@ -0,0 +1,49 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +select ca_zip + ,sum(cs_sales_price) + from catalog_sales + ,customer + ,customer_address + ,date_dim + where cs_bill_customer_sk = c_customer_sk + and c_current_addr_sk = ca_address_sk + and ( substr(ca_zip,1,5) in ('85669', '86197','88274','83405','86475', + '85392', '85460', '80348', '81792') + or ca_state in ('CA','WA','GA') + or cs_sales_price > 500) + and cs_sold_date_sk = d_date_sk + and d_qoy = 1 and d_year = 2001 + group by ca_zip + order by ca_zip + limit 100; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("ca_zip")) + assertTrue(topPlan.contains("__sum_1")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query2.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query2.groovy new file mode 100644 index 00000000000000..8ea2ff18a9a65e --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query2.groovy @@ -0,0 +1,94 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +with wscs as + (select sold_date_sk + ,sales_price + from (select ws_sold_date_sk sold_date_sk + ,ws_ext_sales_price sales_price + from web_sales + union all + select cs_sold_date_sk sold_date_sk + ,cs_ext_sales_price sales_price + from catalog_sales) t), + wswscs as + (select d_week_seq, + sum(case when (d_day_name='Sunday') then sales_price else null end) sun_sales, + sum(case when (d_day_name='Monday') then sales_price else null end) mon_sales, + sum(case when (d_day_name='Tuesday') then sales_price else null end) tue_sales, + sum(case when (d_day_name='Wednesday') then sales_price else null end) wed_sales, + sum(case when (d_day_name='Thursday') then sales_price else null end) thu_sales, + sum(case when (d_day_name='Friday') then sales_price else null end) fri_sales, + sum(case when (d_day_name='Saturday') then sales_price else null end) sat_sales + from wscs + ,date_dim + where d_date_sk = sold_date_sk + group by d_week_seq) + select d_week_seq1 + ,round(sun_sales1/sun_sales2,2) + ,round(mon_sales1/mon_sales2,2) + ,round(tue_sales1/tue_sales2,2) + ,round(wed_sales1/wed_sales2,2) + ,round(thu_sales1/thu_sales2,2) + ,round(fri_sales1/fri_sales2,2) + ,round(sat_sales1/sat_sales2,2) + from + (select wswscs.d_week_seq d_week_seq1 + ,sun_sales sun_sales1 + ,mon_sales mon_sales1 + ,tue_sales tue_sales1 + ,wed_sales wed_sales1 + ,thu_sales thu_sales1 + ,fri_sales fri_sales1 + ,sat_sales sat_sales1 + from wswscs,date_dim + where date_dim.d_week_seq = wswscs.d_week_seq and + d_year = 1998) y, + (select wswscs.d_week_seq d_week_seq2 + ,sun_sales sun_sales2 + ,mon_sales mon_sales2 + ,tue_sales tue_sales2 + ,wed_sales wed_sales2 + ,thu_sales thu_sales2 + ,fri_sales fri_sales2 + ,sat_sales sat_sales2 + from wswscs + ,date_dim + where date_dim.d_week_seq = wswscs.d_week_seq and + d_year = 1998+1) z + where d_week_seq1=d_week_seq2-53 + order by d_week_seq1;""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("d_week_seq1")) + assertTrue(topPlan.contains("__round_1")) + assertTrue(topPlan.contains("__round_2")) + assertTrue(topPlan.contains("__round_3")) + assertTrue(topPlan.contains("__round_4")) + assertTrue(topPlan.contains("__round_5")) + assertTrue(topPlan.contains("__round_6")) + assertTrue(topPlan.contains("__round_7")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query23.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query23.groovy new file mode 100644 index 00000000000000..0480d314e312c1 --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query23.groovy @@ -0,0 +1,80 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +with frequent_ss_items as + (select substr(i_item_desc,1,30) itemdesc,i_item_sk item_sk,d_date solddate,count(*) cnt + from store_sales + ,date_dim + ,item + where ss_sold_date_sk = d_date_sk + and ss_item_sk = i_item_sk + and d_year in (2000,2000+1,2000+2,2000+3) + group by substr(i_item_desc,1,30),i_item_sk,d_date + having count(*) >4), + max_store_sales as + (select max(csales) tpcds_cmax + from (select c_customer_sk,sum(ss_quantity*ss_sales_price) csales + from store_sales + ,customer + ,date_dim + where ss_customer_sk = c_customer_sk + and ss_sold_date_sk = d_date_sk + and d_year in (2000,2000+1,2000+2,2000+3) + group by c_customer_sk) t), + best_ss_customer as + (select c_customer_sk,sum(ss_quantity*ss_sales_price) ssales + from store_sales + ,customer + where ss_customer_sk = c_customer_sk + group by c_customer_sk + having sum(ss_quantity*ss_sales_price) > (95/100.0) * (select + * +from + max_store_sales)) + select sum(sales) + from (select cs_quantity*cs_list_price sales + from catalog_sales + ,date_dim + where d_year = 2000 + and d_moy = 5 + and cs_sold_date_sk = d_date_sk + and cs_item_sk in (select item_sk from frequent_ss_items) + and cs_bill_customer_sk in (select c_customer_sk from best_ss_customer) + union all + select ws_quantity*ws_list_price sales + from web_sales + ,date_dim + where d_year = 2000 + and d_moy = 5 + and ws_sold_date_sk = d_date_sk + and ws_item_sk in (select item_sk from frequent_ss_items) + and ws_bill_customer_sk in (select c_customer_sk from best_ss_customer)) t2 + limit 100; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("__sum_0")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query35.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query35.groovy new file mode 100644 index 00000000000000..f10efec6dbff5d --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query35.groovy @@ -0,0 +1,102 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +select + ca_state, + cd_gender, + cd_marital_status, + cd_dep_count, + count(*) cnt1, + max(cd_dep_count), + sum(cd_dep_count), + max(cd_dep_count), + cd_dep_employed_count, + count(*) cnt2, + max(cd_dep_employed_count), + sum(cd_dep_employed_count), + max(cd_dep_employed_count), + cd_dep_college_count, + count(*) cnt3, + max(cd_dep_college_count), + sum(cd_dep_college_count), + max(cd_dep_college_count) + from + customer c,customer_address ca,customer_demographics + where + c.c_current_addr_sk = ca.ca_address_sk and + cd_demo_sk = c.c_current_cdemo_sk and + exists (select * + from store_sales,date_dim + where c.c_customer_sk = ss_customer_sk and + ss_sold_date_sk = d_date_sk and + d_year = 2001 and + d_qoy < 4) and + (exists (select * + from web_sales,date_dim + where c.c_customer_sk = ws_bill_customer_sk and + ws_sold_date_sk = d_date_sk and + d_year = 2001 and + d_qoy < 4) or + exists (select * + from catalog_sales,date_dim + where c.c_customer_sk = cs_ship_customer_sk and + cs_sold_date_sk = d_date_sk and + d_year = 2001 and + d_qoy < 4)) + group by ca_state, + cd_gender, + cd_marital_status, + cd_dep_count, + cd_dep_employed_count, + cd_dep_college_count + order by ca_state, + cd_gender, + cd_marital_status, + cd_dep_count, + cd_dep_employed_count, + cd_dep_college_count + limit 100; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("ca_state")) + assertTrue(topPlan.contains("cd_gender")) + assertTrue(topPlan.contains("cd_marital_status")) + assertTrue(topPlan.contains("cd_dep_count")) + assertTrue(topPlan.contains("cnt1")) + assertTrue(topPlan.contains("__max_5")) + assertTrue(topPlan.contains("__sum_6")) + assertTrue(topPlan.contains("__max_7")) + assertTrue(topPlan.contains("cd_dep_employed_count")) + assertTrue(topPlan.contains("cnt2")) + assertTrue(topPlan.contains("__max_10")) + assertTrue(topPlan.contains("__sum_11")) + assertTrue(topPlan.contains("__max_12")) + assertTrue(topPlan.contains("cd_dep_college_count")) + assertTrue(topPlan.contains("cnt3")) + assertTrue(topPlan.contains("__sum_16")) + assertTrue(topPlan.contains("__max_17")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query38.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query38.groovy new file mode 100644 index 00000000000000..a1182b55c34e1e --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query38.groovy @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +select count(*) from ( + select distinct c_last_name, c_first_name, d_date + from store_sales, date_dim, customer + where store_sales.ss_sold_date_sk = date_dim.d_date_sk + and store_sales.ss_customer_sk = customer.c_customer_sk + and d_month_seq between 1183 and 1183 + 11 + intersect + select distinct c_last_name, c_first_name, d_date + from catalog_sales, date_dim, customer + where catalog_sales.cs_sold_date_sk = date_dim.d_date_sk + and catalog_sales.cs_bill_customer_sk = customer.c_customer_sk + and d_month_seq between 1183 and 1183 + 11 + intersect + select distinct c_last_name, c_first_name, d_date + from web_sales, date_dim, customer + where web_sales.ws_sold_date_sk = date_dim.d_date_sk + and web_sales.ws_bill_customer_sk = customer.c_customer_sk + and d_month_seq between 1183 and 1183 + 11 +) hot_cust +limit 100; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("__count_0")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query41.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query41.groovy new file mode 100644 index 00000000000000..46a8a7909ca523 --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query41.groovy @@ -0,0 +1,80 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +select distinct(i_product_name) + from item i1 + where i_manufact_id between 748 and 748+40 + and (select count(*) as item_cnt + from item + where (i_manufact = i1.i_manufact and + ((i_category = 'Women' and + (i_color = 'gainsboro' or i_color = 'aquamarine') and + (i_units = 'Ounce' or i_units = 'Dozen') and + (i_size = 'medium' or i_size = 'economy') + ) or + (i_category = 'Women' and + (i_color = 'chiffon' or i_color = 'violet') and + (i_units = 'Ton' or i_units = 'Pound') and + (i_size = 'extra large' or i_size = 'small') + ) or + (i_category = 'Men' and + (i_color = 'chartreuse' or i_color = 'blue') and + (i_units = 'Each' or i_units = 'Oz') and + (i_size = 'N/A' or i_size = 'large') + ) or + (i_category = 'Men' and + (i_color = 'tan' or i_color = 'dodger') and + (i_units = 'Bunch' or i_units = 'Tsp') and + (i_size = 'medium' or i_size = 'economy') + ))) or + (i_manufact = i1.i_manufact and + ((i_category = 'Women' and + (i_color = 'blanched' or i_color = 'tomato') and + (i_units = 'Tbl' or i_units = 'Case') and + (i_size = 'medium' or i_size = 'economy') + ) or + (i_category = 'Women' and + (i_color = 'almond' or i_color = 'lime') and + (i_units = 'Box' or i_units = 'Dram') and + (i_size = 'extra large' or i_size = 'small') + ) or + (i_category = 'Men' and + (i_color = 'peru' or i_color = 'saddle') and + (i_units = 'Pallet' or i_units = 'Gram') and + (i_size = 'N/A' or i_size = 'large') + ) or + (i_category = 'Men' and + (i_color = 'indian' or i_color = 'spring') and + (i_units = 'Unknown' or i_units = 'Carton') and + (i_size = 'medium' or i_size = 'economy') + )))) > 0 + order by i_product_name + limit 100; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("i_product_name")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query42.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query42.groovy new file mode 100644 index 00000000000000..045b8202a13128 --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query42.groovy @@ -0,0 +1,53 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +select dt.d_year + ,item.i_category_id + ,item.i_category + ,sum(ss_ext_sales_price) + from date_dim dt + ,store_sales + ,item + where dt.d_date_sk = store_sales.ss_sold_date_sk + and store_sales.ss_item_sk = item.i_item_sk + and item.i_manager_id = 1 + and dt.d_moy=11 + and dt.d_year=2002 + group by dt.d_year + ,item.i_category_id + ,item.i_category + order by sum(ss_ext_sales_price) desc,dt.d_year + ,item.i_category_id + ,item.i_category +limit 100 ; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("d_year")) + assertTrue(topPlan.contains("i_category_id")) + assertTrue(topPlan.contains("i_category")) + assertTrue(topPlan.contains("__sum_3")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query45.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query45.groovy new file mode 100644 index 00000000000000..d0203b6650890f --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query45.groovy @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +select ca_zip, ca_city, sum(ws_sales_price) + from web_sales, customer, customer_address, date_dim, item + where ws_bill_customer_sk = c_customer_sk + and c_current_addr_sk = ca_address_sk + and ws_item_sk = i_item_sk + and ( substr(ca_zip,1,5) in ('85669', '86197','88274','83405','86475', '85392', '85460', '80348', '81792') + or + i_item_id in (select i_item_id + from item + where i_item_sk in (2, 3, 5, 7, 11, 13, 17, 19, 23, 29) + ) + ) + and ws_sold_date_sk = d_date_sk + and d_qoy = 2 and d_year = 2000 + group by ca_zip, ca_city + order by ca_zip, ca_city + limit 100; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("ca_zip")) + assertTrue(topPlan.contains("ca_city")) + assertTrue(topPlan.contains("__sum_2")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query59.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query59.groovy new file mode 100644 index 00000000000000..7df0d53bc53223 --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query59.groovy @@ -0,0 +1,81 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +with wss as + (select d_week_seq, + ss_store_sk, + sum(case when (d_day_name='Sunday') then ss_sales_price else null end) sun_sales, + sum(case when (d_day_name='Monday') then ss_sales_price else null end) mon_sales, + sum(case when (d_day_name='Tuesday') then ss_sales_price else null end) tue_sales, + sum(case when (d_day_name='Wednesday') then ss_sales_price else null end) wed_sales, + sum(case when (d_day_name='Thursday') then ss_sales_price else null end) thu_sales, + sum(case when (d_day_name='Friday') then ss_sales_price else null end) fri_sales, + sum(case when (d_day_name='Saturday') then ss_sales_price else null end) sat_sales + from store_sales,date_dim + where d_date_sk = ss_sold_date_sk + group by d_week_seq,ss_store_sk + ) + select s_store_name1,s_store_id1,d_week_seq1 + ,sun_sales1/sun_sales2,mon_sales1/mon_sales2 + ,tue_sales1/tue_sales2,wed_sales1/wed_sales2,thu_sales1/thu_sales2 + ,fri_sales1/fri_sales2,sat_sales1/sat_sales2 + from + (select s_store_name s_store_name1,wss.d_week_seq d_week_seq1 + ,s_store_id s_store_id1,sun_sales sun_sales1 + ,mon_sales mon_sales1,tue_sales tue_sales1 + ,wed_sales wed_sales1,thu_sales thu_sales1 + ,fri_sales fri_sales1,sat_sales sat_sales1 + from wss,store,date_dim d + where d.d_week_seq = wss.d_week_seq and + ss_store_sk = s_store_sk and + d_month_seq between 1196 and 1196 + 11) y, + (select s_store_name s_store_name2,wss.d_week_seq d_week_seq2 + ,s_store_id s_store_id2,sun_sales sun_sales2 + ,mon_sales mon_sales2,tue_sales tue_sales2 + ,wed_sales wed_sales2,thu_sales thu_sales2 + ,fri_sales fri_sales2,sat_sales sat_sales2 + from wss,store,date_dim d + where d.d_week_seq = wss.d_week_seq and + ss_store_sk = s_store_sk and + d_month_seq between 1196+ 12 and 1196 + 23) x + where s_store_id1=s_store_id2 + and d_week_seq1=d_week_seq2-52 + order by s_store_name1,s_store_id1,d_week_seq1 +limit 100; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("s_store_name1")) + assertTrue(topPlan.contains("s_store_id1")) + assertTrue(topPlan.contains("d_week_seq1")) + assertTrue(topPlan.contains("__divide_3")) + assertTrue(topPlan.contains("__divide_4")) + assertTrue(topPlan.contains("__divide_5")) + assertTrue(topPlan.contains("__divide_6")) + assertTrue(topPlan.contains("__divide_7")) + assertTrue(topPlan.contains("__divide_8")) + assertTrue(topPlan.contains("__divide_9")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query61.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query61.groovy new file mode 100644 index 00000000000000..2aa572e5b23e0b --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query61.groovy @@ -0,0 +1,74 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +select promotions,total,cast(promotions as decimal(15,4))/cast(total as decimal(15,4))*100 +from + (select sum(ss_ext_sales_price) promotions + from store_sales + ,store + ,promotion + ,date_dim + ,customer + ,customer_address + ,item + where ss_sold_date_sk = d_date_sk + and ss_store_sk = s_store_sk + and ss_promo_sk = p_promo_sk + and ss_customer_sk= c_customer_sk + and ca_address_sk = c_current_addr_sk + and ss_item_sk = i_item_sk + and ca_gmt_offset = -7 + and i_category = 'Jewelry' + and (p_channel_dmail = 'Y' or p_channel_email = 'Y' or p_channel_tv = 'Y') + and s_gmt_offset = -7 + and d_year = 1999 + and d_moy = 11) promotional_sales, + (select sum(ss_ext_sales_price) total + from store_sales + ,store + ,date_dim + ,customer + ,customer_address + ,item + where ss_sold_date_sk = d_date_sk + and ss_store_sk = s_store_sk + and ss_customer_sk= c_customer_sk + and ca_address_sk = c_current_addr_sk + and ss_item_sk = i_item_sk + and ca_gmt_offset = -7 + and i_category = 'Jewelry' + and s_gmt_offset = -7 + and d_year = 1999 + and d_moy = 11) all_sales +order by promotions, total +limit 100; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("promotions")) + assertTrue(topPlan.contains("total")) + assertTrue(topPlan.contains("__multiply_2")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query62.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query62.groovy new file mode 100644 index 00000000000000..47c2924afd7978 --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query62.groovy @@ -0,0 +1,63 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +select + substr(w_warehouse_name,1,20) + ,sm_type + ,web_name + ,sum(case when (ws_ship_date_sk - ws_sold_date_sk <= 30 ) then 1 else 0 end) as "30 days" + ,sum(case when (ws_ship_date_sk - ws_sold_date_sk > 30) and + (ws_ship_date_sk - ws_sold_date_sk <= 60) then 1 else 0 end ) as "31-60 days" + ,sum(case when (ws_ship_date_sk - ws_sold_date_sk > 60) and + (ws_ship_date_sk - ws_sold_date_sk <= 90) then 1 else 0 end) as "61-90 days" + ,sum(case when (ws_ship_date_sk - ws_sold_date_sk > 90) and + (ws_ship_date_sk - ws_sold_date_sk <= 120) then 1 else 0 end) as "91-120 days" + ,sum(case when (ws_ship_date_sk - ws_sold_date_sk > 120) then 1 else 0 end) as ">120 days" +from + web_sales + ,warehouse + ,ship_mode + ,web_site + ,date_dim +where + d_month_seq between 1194 and 1194 + 11 +and ws_ship_date_sk = d_date_sk +and ws_warehouse_sk = w_warehouse_sk +and ws_ship_mode_sk = sm_ship_mode_sk +and ws_web_site_sk = web_site_sk +group by + substr(w_warehouse_name,1,20) + ,sm_type + ,web_name +order by substr(w_warehouse_name,1,20) + ,sm_type + ,web_name +limit 100; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("__substring_0")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query8.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query8.groovy new file mode 100644 index 00000000000000..c73af1e1c49aac --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query8.groovy @@ -0,0 +1,136 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +select s_store_name + ,sum(ss_net_profit) + from store_sales + ,date_dim + ,store, + (select ca_zip + from ( + SELECT substr(ca_zip,1,5) ca_zip + FROM customer_address + WHERE substr(ca_zip,1,5) IN ( + '47602','16704','35863','28577','83910','36201', + '58412','48162','28055','41419','80332', + '38607','77817','24891','16226','18410', + '21231','59345','13918','51089','20317', + '17167','54585','67881','78366','47770', + '18360','51717','73108','14440','21800', + '89338','45859','65501','34948','25973', + '73219','25333','17291','10374','18829', + '60736','82620','41351','52094','19326', + '25214','54207','40936','21814','79077', + '25178','75742','77454','30621','89193', + '27369','41232','48567','83041','71948', + '37119','68341','14073','16891','62878', + '49130','19833','24286','27700','40979', + '50412','81504','94835','84844','71954', + '39503','57649','18434','24987','12350', + '86379','27413','44529','98569','16515', + '27287','24255','21094','16005','56436', + '91110','68293','56455','54558','10298', + '83647','32754','27052','51766','19444', + '13869','45645','94791','57631','20712', + '37788','41807','46507','21727','71836', + '81070','50632','88086','63991','20244', + '31655','51782','29818','63792','68605', + '94898','36430','57025','20601','82080', + '33869','22728','35834','29086','92645', + '98584','98072','11652','78093','57553', + '43830','71144','53565','18700','90209', + '71256','38353','54364','28571','96560', + '57839','56355','50679','45266','84680', + '34306','34972','48530','30106','15371', + '92380','84247','92292','68852','13338', + '34594','82602','70073','98069','85066', + '47289','11686','98862','26217','47529', + '63294','51793','35926','24227','14196', + '24594','32489','99060','49472','43432', + '49211','14312','88137','47369','56877', + '20534','81755','15794','12318','21060', + '73134','41255','63073','81003','73873', + '66057','51184','51195','45676','92696', + '70450','90669','98338','25264','38919', + '59226','58581','60298','17895','19489', + '52301','80846','95464','68770','51634', + '19988','18367','18421','11618','67975', + '25494','41352','95430','15734','62585', + '97173','33773','10425','75675','53535', + '17879','41967','12197','67998','79658', + '59130','72592','14851','43933','68101', + '50636','25717','71286','24660','58058', + '72991','95042','15543','33122','69280', + '11912','59386','27642','65177','17672', + '33467','64592','36335','54010','18767', + '63193','42361','49254','33113','33159', + '36479','59080','11855','81963','31016', + '49140','29392','41836','32958','53163', + '13844','73146','23952','65148','93498', + '14530','46131','58454','13376','13378', + '83986','12320','17193','59852','46081', + '98533','52389','13086','68843','31013', + '13261','60560','13443','45533','83583', + '11489','58218','19753','22911','25115', + '86709','27156','32669','13123','51933', + '39214','41331','66943','14155','69998', + '49101','70070','35076','14242','73021', + '59494','15782','29752','37914','74686', + '83086','34473','15751','81084','49230', + '91894','60624','17819','28810','63180', + '56224','39459','55233','75752','43639', + '55349','86057','62361','50788','31830', + '58062','18218','85761','60083','45484', + '21204','90229','70041','41162','35390', + '16364','39500','68908','26689','52868', + '81335','40146','11340','61527','61794', + '71997','30415','59004','29450','58117', + '69952','33562','83833','27385','61860', + '96435','48333','23065','32961','84919', + '61997','99132','22815','56600','68730', + '48017','95694','32919','88217','27116', + '28239','58032','18884','16791','21343', + '97462','18569','75660','15475') + intersect + select ca_zip + from (SELECT substr(ca_zip,1,5) ca_zip,count(*) cnt + FROM customer_address, customer + WHERE ca_address_sk = c_current_addr_sk and + c_preferred_cust_flag='Y' + group by ca_zip + having count(*) > 10)A1)A2) V1 + where ss_store_sk = s_store_sk + and ss_sold_date_sk = d_date_sk + and d_qoy = 2 and d_year = 1998 + and (substr(s_zip,1,2) = substr(V1.ca_zip,1,2)) + group by s_store_name + order by s_store_name + limit 100;""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("s_store_name")) + assertTrue(topPlan.contains("__sum_1")) +} \ No newline at end of file diff --git a/regression-test/suites/nereids_p0/infer_expr_name/query85.groovy b/regression-test/suites/nereids_p0/infer_expr_name/query85.groovy new file mode 100644 index 00000000000000..88970ce6b1a881 --- /dev/null +++ b/regression-test/suites/nereids_p0/infer_expr_name/query85.groovy @@ -0,0 +1,115 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package infer_expr_name + +suite("nereids_test_create_blocked") { + sql 'set enable_nereids_planner=true' + sql 'set enable_fallback_to_original_planner=false' + + def queryResult = sql """ +explain analyzed plan +select substr(r_reason_desc,1,20) + ,avg(ws_quantity) + ,avg(wr_refunded_cash) + ,avg(wr_fee) + from web_sales, web_returns, web_page, customer_demographics cd1, + customer_demographics cd2, customer_address, date_dim, reason + where ws_web_page_sk = wp_web_page_sk + and ws_item_sk = wr_item_sk + and ws_order_number = wr_order_number + and ws_sold_date_sk = d_date_sk and d_year = 2000 + and cd1.cd_demo_sk = wr_refunded_cdemo_sk + and cd2.cd_demo_sk = wr_returning_cdemo_sk + and ca_address_sk = wr_refunded_addr_sk + and r_reason_sk = wr_reason_sk + and + ( + ( + cd1.cd_marital_status = 'M' + and + cd1.cd_marital_status = cd2.cd_marital_status + and + cd1.cd_education_status = '4 yr Degree' + and + cd1.cd_education_status = cd2.cd_education_status + and + ws_sales_price between 100.00 and 150.00 + ) + or + ( + cd1.cd_marital_status = 'S' + and + cd1.cd_marital_status = cd2.cd_marital_status + and + cd1.cd_education_status = 'Secondary' + and + cd1.cd_education_status = cd2.cd_education_status + and + ws_sales_price between 50.00 and 100.00 + ) + or + ( + cd1.cd_marital_status = 'W' + and + cd1.cd_marital_status = cd2.cd_marital_status + and + cd1.cd_education_status = 'Advanced Degree' + and + cd1.cd_education_status = cd2.cd_education_status + and + ws_sales_price between 150.00 and 200.00 + ) + ) + and + ( + ( + ca_country = 'United States' + and + ca_state in ('FL', 'TX', 'DE') + and ws_net_profit between 100 and 200 + ) + or + ( + ca_country = 'United States' + and + ca_state in ('IN', 'ND', 'ID') + and ws_net_profit between 150 and 300 + ) + or + ( + ca_country = 'United States' + and + ca_state in ('MT', 'IL', 'OH') + and ws_net_profit between 50 and 250 + ) + ) +group by r_reason_desc +order by substr(r_reason_desc,1,20) + ,avg(ws_quantity) + ,avg(wr_refunded_cash) + ,avg(wr_fee) +limit 100; +""" + + def topPlan = queryResult[0][0].toString() + assertTrue(topPlan.contains("LogicalResultSink")) + assertTrue(topPlan.contains("__substring_0")) + assertTrue(topPlan.contains("__avg_1")) + assertTrue(topPlan.contains("__avg_2")) + assertTrue(topPlan.contains("__avg_3")) +} \ No newline at end of file From a2419a8eb408c0c890d48e0905ee199eb3deb9a5 Mon Sep 17 00:00:00 2001 From: Yongqiang YANG <98214048+dataroaring@users.noreply.github.com> Date: Wed, 8 Nov 2023 11:51:40 +0800 Subject: [PATCH 35/88] [enhancement](sink) refactor code of auto partition and where clause and enable them on sinkv2 (#26432) For better performance and elasticity, we move memtable from loadchannel to sink, VTabletSinkV2 is introduced, then there are VTabletWriter and VTabletSinkV2 distributing rows to tablets. where clauses on mvs are executed in VTabletWriter, while VTabletSinkV2 needs it too. So common code is moved to row distribution. Actually, we can layer code by rows' data flow, then the code is much more understood and maintainable. ScanNode -> Sink/Writer (RowDistribution -> IndexChannel / DeltaWriter) --- be/src/vec/sink/vrow_distribution.cpp | 306 ++++++++++++++++ be/src/vec/sink/vrow_distribution.h | 160 +++++++++ be/src/vec/sink/vtablet_sink_v2.cpp | 101 +++--- be/src/vec/sink/vtablet_sink_v2.h | 22 +- be/src/vec/sink/writer/vtablet_writer.cpp | 408 +++++----------------- be/src/vec/sink/writer/vtablet_writer.h | 37 +- 6 files changed, 655 insertions(+), 379 deletions(-) create mode 100644 be/src/vec/sink/vrow_distribution.cpp create mode 100644 be/src/vec/sink/vrow_distribution.h diff --git a/be/src/vec/sink/vrow_distribution.cpp b/be/src/vec/sink/vrow_distribution.cpp new file mode 100644 index 00000000000000..78d3b062045648 --- /dev/null +++ b/be/src/vec/sink/vrow_distribution.cpp @@ -0,0 +1,306 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include "vec/sink/vrow_distribution.h" + +#include +#include + +#include "runtime/client_cache.h" +#include "runtime/exec_env.h" +#include "runtime/runtime_state.h" +#include "util/thrift_rpc_helper.h" +#include "vec/columns/column_const.h" +#include "vec/columns/column_nullable.h" +#include "vec/columns/column_vector.h" +#include "vec/sink/writer/vtablet_writer.h" + +namespace doris::vectorized { + +std::pair +VRowDistribution::_get_partition_function() { + return {_vpartition->get_part_func_ctx(), _vpartition->get_partition_function()}; +} + +void VRowDistribution::_save_missing_values(vectorized::ColumnPtr col, + vectorized::DataTypePtr value_type) { + _partitions_need_create.clear(); + std::set deduper; + // de-duplication + for (auto row : _missing_map) { + deduper.emplace(value_type->to_string(*col, row)); + } + for (auto& value : deduper) { + TStringLiteral node; + node.value = value; + _partitions_need_create.emplace_back(std::vector {node}); // only 1 partition column now + } +} + +Status VRowDistribution::_automatic_create_partition() { + SCOPED_TIMER(_add_partition_request_timer); + TCreatePartitionRequest request; + TCreatePartitionResult result; + request.__set_txn_id(_txn_id); + request.__set_db_id(_vpartition->db_id()); + request.__set_table_id(_vpartition->table_id()); + request.__set_partitionValues(_partitions_need_create); + + VLOG(1) << "automatic partition rpc begin request " << request; + TNetworkAddress master_addr = ExecEnv::GetInstance()->master_info()->network_address; + int time_out = _state->execution_timeout() * 1000; + RETURN_IF_ERROR(ThriftRpcHelper::rpc( + master_addr.hostname, master_addr.port, + [&request, &result](FrontendServiceConnection& client) { + client->createPartition(result, request); + }, + time_out)); + + Status status(Status::create(result.status)); + VLOG(1) << "automatic partition rpc end response " << result; + if (result.status.status_code == TStatusCode::OK) { + // add new created partitions + RETURN_IF_ERROR(_vpartition->add_partitions(result.partitions)); + RETURN_IF_ERROR(_on_partitions_created(_caller, &result)); + } + + return status; +} + +void VRowDistribution::_get_tablet_ids(vectorized::Block* block, int32_t index_idx, + std::vector& tablet_ids) { + tablet_ids.reserve(block->rows()); + for (int row_idx = 0; row_idx < block->rows(); row_idx++) { + if (_skip[row_idx]) { + continue; + } + auto& partition = _partitions[row_idx]; + auto& tablet_index = _tablet_indexes[row_idx]; + auto& index = partition->indexes[index_idx]; + + auto tablet_id = index.tablets[tablet_index]; + tablet_ids[row_idx] = tablet_id; + } +} + +void VRowDistribution::_filter_block_by_skip(vectorized::Block* block, + RowPartTabletIds& row_part_tablet_id) { + auto& row_ids = row_part_tablet_id.row_ids; + auto& partition_ids = row_part_tablet_id.partition_ids; + auto& tablet_ids = row_part_tablet_id.tablet_ids; + + for (size_t i = 0; i < block->rows(); i++) { + if (!_skip[i]) { + row_ids.emplace_back(i); + partition_ids.emplace_back(_partitions[i]->id); + tablet_ids.emplace_back(_tablet_ids[i]); + } + } +} + +Status VRowDistribution::_filter_block_by_skip_and_where_clause( + vectorized::Block* block, const vectorized::VExprContextSPtr& where_clause, + RowPartTabletIds& row_part_tablet_id) { + // TODO + //SCOPED_RAW_TIMER(&_stat.where_clause_ns); + int result_index = -1; + size_t column_number = block->columns(); + RETURN_IF_ERROR(where_clause->execute(block, &result_index)); + + auto filter_column = block->get_by_position(result_index).column; + + auto& row_ids = row_part_tablet_id.row_ids; + auto& partition_ids = row_part_tablet_id.partition_ids; + auto& tablet_ids = row_part_tablet_id.tablet_ids; + if (auto* nullable_column = + vectorized::check_and_get_column(*filter_column)) { + for (size_t i = 0; i < block->rows(); i++) { + if (nullable_column->get_bool_inline(i) && !_skip[i]) { + row_ids.emplace_back(i); + partition_ids.emplace_back(_partitions[i]->id); + tablet_ids.emplace_back(_tablet_ids[i]); + } + } + } else if (auto* const_column = + vectorized::check_and_get_column(*filter_column)) { + bool ret = const_column->get_bool(0); + if (!ret) { + return Status::OK(); + } + // should we optimize? + _filter_block_by_skip(block, row_part_tablet_id); + } else { + auto& filter = assert_cast(*filter_column).get_data(); + for (size_t i = 0; i < block->rows(); i++) { + if (filter[i] != 0 && !_skip[i]) { + row_ids.emplace_back(i); + partition_ids.emplace_back(_partitions[i]->id); + tablet_ids.emplace_back(_tablet_ids[i]); + } + } + } + + for (size_t i = block->columns() - 1; i >= column_number; i--) { + block->erase(i); + } + return Status::OK(); +} + +Status VRowDistribution::_filter_block(vectorized::Block* block, + std::vector& row_part_tablet_ids) { + for (int i = 0; i < _schema->indexes().size(); i++) { + _get_tablet_ids(block, i, _tablet_ids); + auto& where_clause = _schema->indexes()[i]->where_clause; + if (where_clause != nullptr) { + RETURN_IF_ERROR(_filter_block_by_skip_and_where_clause(block, where_clause, + row_part_tablet_ids[i])); + } else { + _filter_block_by_skip(block, row_part_tablet_ids[i]); + } + } + return Status::OK(); +} + +Status VRowDistribution::_generate_rows_distribution_for_non_auto_parititon( + vectorized::Block* block, bool has_filtered_rows, + std::vector& row_part_tablet_ids) { + auto num_rows = block->rows(); + + bool stop_processing = false; + RETURN_IF_ERROR(_tablet_finder->find_tablets(_state, block, num_rows, _partitions, + _tablet_indexes, stop_processing, _skip)); + if (has_filtered_rows) { + for (int i = 0; i < num_rows; i++) { + _skip[i] = _skip[i] || _block_convertor->filter_map()[i]; + } + } + RETURN_IF_ERROR(_filter_block(block, row_part_tablet_ids)); + return Status::OK(); +} + +Status VRowDistribution::_generate_rows_distribution_for_auto_parititon( + vectorized::Block* block, int partition_col_idx, bool has_filtered_rows, + std::vector& row_part_tablet_ids) { + auto num_rows = block->rows(); + std::vector partition_keys = _vpartition->get_partition_keys(); + + //TODO: use loop to create missing_vals for multi column. + CHECK(partition_keys.size() == 1) << "now support only 1 partition column for auto partitions."; + auto partition_col = block->get_by_position(partition_keys[0]); + _missing_map.clear(); + _missing_map.reserve(partition_col.column->size()); + bool stop_processing = false; + //TODO: we could use the buffer to save tablets we found so that no need to find them again when we created partitions and try to append block next time. + RETURN_IF_ERROR(_tablet_finder->find_tablets(_state, block, num_rows, _partitions, + _tablet_indexes, stop_processing, _skip, + &_missing_map)); + if (_missing_map.empty()) { + // we don't calculate it distribution when have missing values + if (has_filtered_rows) { + for (int i = 0; i < num_rows; i++) { + _skip[i] = _skip[i] || _block_convertor->filter_map()[i]; + } + } + RETURN_IF_ERROR(_filter_block(block, row_part_tablet_ids)); + } else { // for missing partition keys, calc the missing partition and save in _partitions_need_create + auto [part_ctx, part_func] = _get_partition_function(); + auto return_type = part_func->data_type(); + + // expose the data column + vectorized::ColumnPtr range_left_col = block->get_by_position(partition_col_idx).column; + if (const auto* nullable = + check_and_get_column(*range_left_col)) { + range_left_col = nullable->get_nested_column_ptr(); + return_type = assert_cast(return_type.get()) + ->get_nested_type(); + } + // calc the end value and save them. + _save_missing_values(range_left_col, return_type); + // then call FE to create it. then FragmentExecutor will redo the load. + RETURN_IF_ERROR(_automatic_create_partition()); + // In the next round, we will _generate_rows_distribution_payload again to get right payload of new tablet + LOG(INFO) << "Auto created partition. Send block again."; + return Status::NeedSendAgain(""); + } // creating done + + return Status::OK(); +} + +void VRowDistribution::_reset_row_part_tablet_ids( + std::vector& row_part_tablet_ids, int64_t rows) { + row_part_tablet_ids.resize(_schema->indexes().size()); + for (auto& row_part_tablet_id : row_part_tablet_ids) { + auto& row_ids = row_part_tablet_id.row_ids; + auto& partition_ids = row_part_tablet_id.partition_ids; + auto& tablet_ids = row_part_tablet_id.tablet_ids; + + row_ids.clear(); + partition_ids.clear(); + tablet_ids.clear(); + row_ids.reserve(rows); + partition_ids.reserve(rows); + tablet_ids.reserve(rows); + } +} + +Status VRowDistribution::generate_rows_distribution( + vectorized::Block& input_block, std::shared_ptr& block, + int64_t& filtered_rows, bool& has_filtered_rows, + std::vector& row_part_tablet_ids) { + auto input_rows = input_block.rows(); + _reset_row_part_tablet_ids(row_part_tablet_ids, input_rows); + + int64_t prev_filtered_rows = + _block_convertor->num_filtered_rows() + _tablet_finder->num_filtered_rows(); + RETURN_IF_ERROR(_block_convertor->validate_and_convert_block( + _state, &input_block, block, *_vec_output_expr_ctxs, input_rows, has_filtered_rows)); + + _tablet_finder->clear_for_new_batch(); + _row_distribution_watch.start(); + auto num_rows = block->rows(); + _tablet_finder->filter_bitmap().Reset(num_rows); + + //reuse vars for find_tablets + _partitions.assign(num_rows, nullptr); + _skip.assign(num_rows, false); + _tablet_indexes.assign(num_rows, 0); + + // if there's projection of partition calc, we need to calc it first. + auto [part_ctx, part_func] = _get_partition_function(); + int partition_col_idx = -1; + if (_vpartition->is_projection_partition()) { + // calc the start value of missing partition ranges. + RETURN_IF_ERROR(part_func->execute(part_ctx.get(), block.get(), &partition_col_idx)); + VLOG_DEBUG << "Partition-calculated block:" << block->dump_data(); + // change the column to compare to transformed. + _vpartition->set_transformed_slots({(uint16_t)partition_col_idx}); + } + + if (_vpartition->is_auto_partition()) { + RETURN_IF_ERROR(_generate_rows_distribution_for_auto_parititon( + block.get(), partition_col_idx, has_filtered_rows, row_part_tablet_ids)); + } else { // not auto partition + RETURN_IF_ERROR(_generate_rows_distribution_for_non_auto_parititon( + block.get(), has_filtered_rows, row_part_tablet_ids)); + } + _row_distribution_watch.stop(); + filtered_rows = _block_convertor->num_filtered_rows() + _tablet_finder->num_filtered_rows() - + prev_filtered_rows; + return Status::OK(); +} + +} // namespace doris::vectorized diff --git a/be/src/vec/sink/vrow_distribution.h b/be/src/vec/sink/vrow_distribution.h new file mode 100644 index 00000000000000..5da964d44fcbdd --- /dev/null +++ b/be/src/vec/sink/vrow_distribution.h @@ -0,0 +1,160 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#pragma once + +// IWYU pragma: no_include +#include +#include +#include + +#include +#include +#include + +#include "common/status.h" +#include "exec/tablet_info.h" +#include "runtime/types.h" +#include "util/runtime_profile.h" +#include "util/stopwatch.hpp" +#include "vec/core/block.h" +#include "vec/data_types/data_type.h" +#include "vec/exprs/vexpr_fwd.h" +#include "vec/sink/vtablet_block_convertor.h" +#include "vec/sink/vtablet_finder.h" + +namespace doris::vectorized { + +class IndexChannel; +class VNodeChannel; + +// +class RowPartTabletIds { +public: + std::vector row_ids; + std::vector partition_ids; + std::vector tablet_ids; +}; + +typedef Status (*OnPartitionsCreated)(void*, TCreatePartitionResult*); + +class VRowDistributionContext { +public: + RuntimeState* state = nullptr; + OlapTableBlockConvertor* block_convertor = nullptr; + OlapTabletFinder* tablet_finder = nullptr; + VOlapTablePartitionParam* vpartition = nullptr; + RuntimeProfile::Counter* add_partition_request_timer = nullptr; + int64_t txn_id = -1; + ObjectPool* pool; + OlapTableLocationParam* location; + const VExprContextSPtrs* vec_output_expr_ctxs; + OnPartitionsCreated on_partitions_created; + void* caller; + std::shared_ptr schema; +}; + +class VRowDistribution { +public: + VRowDistribution() {} + virtual ~VRowDistribution() {} + + void init(VRowDistributionContext* ctx) { + _state = ctx->state; + _block_convertor = ctx->block_convertor; + _tablet_finder = ctx->tablet_finder; + _vpartition = ctx->vpartition; + _add_partition_request_timer = ctx->add_partition_request_timer; + _txn_id = ctx->txn_id; + _pool = ctx->pool; + _location = ctx->location; + _vec_output_expr_ctxs = ctx->vec_output_expr_ctxs; + _on_partitions_created = ctx->on_partitions_created; + _caller = ctx->caller; + _schema = ctx->schema; + } + + // auto partition + // mv where clause + // v1 needs index->node->row_ids - tabletids + // v2 needs index,tablet->rowids + Status generate_rows_distribution(vectorized::Block& input_block, + std::shared_ptr& block, + int64_t& filtered_rows, bool& has_filtered_rows, + std::vector& row_part_tablet_ids); + +private: + std::pair _get_partition_function(); + + void _save_missing_values(vectorized::ColumnPtr col, vectorized::DataTypePtr value_type); + + // create partitions when need for auto-partition table using #_partitions_need_create. + Status _automatic_create_partition(); + + void _get_tablet_ids(vectorized::Block* block, int32_t index_idx, + std::vector& tablet_ids); + + void _filter_block_by_skip(vectorized::Block* block, RowPartTabletIds& row_part_tablet_id); + + Status _filter_block_by_skip_and_where_clause(vectorized::Block* block, + const vectorized::VExprContextSPtr& where_clause, + RowPartTabletIds& row_part_tablet_id); + + Status _filter_block(vectorized::Block* block, + std::vector& row_part_tablet_ids); + + Status _generate_rows_distribution_for_auto_parititon( + vectorized::Block* block, int partition_col_idx, bool has_filtered_rows, + std::vector& row_part_tablet_ids); + + Status _generate_rows_distribution_for_non_auto_parititon( + vectorized::Block* block, bool has_filtered_rows, + std::vector& row_part_tablet_ids); + + void _reset_row_part_tablet_ids(std::vector& row_part_tablet_ids, + int64_t rows); + +private: + RuntimeState* _state = nullptr; + + // support only one partition column now + std::vector> _partitions_need_create; + + MonotonicStopWatch _row_distribution_watch; + OlapTableBlockConvertor* _block_convertor = nullptr; + OlapTabletFinder* _tablet_finder = nullptr; + VOlapTablePartitionParam* _vpartition = nullptr; + RuntimeProfile::Counter* _add_partition_request_timer = nullptr; + int64_t _txn_id = -1; + ObjectPool* _pool; + OlapTableLocationParam* _location = nullptr; + // std::function _on_partition_created; + // int64_t _number_output_rows = 0; + const VExprContextSPtrs* _vec_output_expr_ctxs; + OnPartitionsCreated _on_partitions_created = nullptr; + void* _caller; + std::shared_ptr _schema; + + // reuse for find_tablet. + std::vector _partitions; + std::vector _skip; + std::vector _tablet_indexes; + std::vector _tablet_ids; + std::vector _missing_map; // indice of missing values in partition_col +}; + +} // namespace doris::vectorized diff --git a/be/src/vec/sink/vtablet_sink_v2.cpp b/be/src/vec/sink/vtablet_sink_v2.cpp index 696a66ac3fbad4..69a372e0e3886f 100644 --- a/be/src/vec/sink/vtablet_sink_v2.cpp +++ b/be/src/vec/sink/vtablet_sink_v2.cpp @@ -77,6 +77,42 @@ VOlapTableSinkV2::VOlapTableSinkV2(ObjectPool* pool, const RowDescriptor& row_de VOlapTableSinkV2::~VOlapTableSinkV2() = default; +Status VOlapTableSinkV2::on_partitions_created(TCreatePartitionResult* result) { + // add new tablet locations. it will use by address. so add to pool + auto* new_locations = _pool->add(new std::vector(result->tablets)); + _location->add_locations(*new_locations); + + // update new node info + _nodes_info->add_nodes(result->nodes); + + // incremental open stream + + return Status::OK(); +} + +static Status on_partitions_created(void* writer, TCreatePartitionResult* result) { + return static_cast(writer)->on_partitions_created(result); +} + +void VOlapTableSinkV2::_init_row_distribution() { + VRowDistributionContext ctx; + + ctx.state = _state; + ctx.block_convertor = _block_convertor.get(); + ctx.tablet_finder = _tablet_finder.get(); + ctx.vpartition = _vpartition; + ctx.add_partition_request_timer = _add_partition_request_timer; + ctx.txn_id = _txn_id; + ctx.pool = _pool; + ctx.location = _location; + ctx.vec_output_expr_ctxs = &_output_vexpr_ctxs; + ctx.on_partitions_created = &vectorized::on_partitions_created; + ctx.caller = (void*)this; + ctx.schema = _schema; + + _row_distribution.init(&ctx); +} + Status VOlapTableSinkV2::init(const TDataSink& t_sink) { DCHECK(t_sink.__isset.olap_table_sink); auto& table_sink = t_sink.olap_table_sink; @@ -104,7 +140,9 @@ Status VOlapTableSinkV2::init(const TDataSink& t_sink) { } _vpartition = _pool->add(new doris::VOlapTablePartitionParam(_schema, table_sink.partition)); _tablet_finder = std::make_unique(_vpartition, find_tablet_mode); - return _vpartition->init(); + RETURN_IF_ERROR(_vpartition->init()); + + return Status::OK(); } Status VOlapTableSinkV2::prepare(RuntimeState* state) { @@ -168,6 +206,7 @@ Status VOlapTableSinkV2::open(RuntimeState* state) { _build_tablet_node_mapping(); RETURN_IF_ERROR(_open_streams(state->backend_id())); + _init_row_distribution(); return Status::OK(); } @@ -222,30 +261,25 @@ void VOlapTableSinkV2::_build_tablet_node_mapping() { } } -void VOlapTableSinkV2::_generate_rows_for_tablet( - RowsForTablet& rows_for_tablet, const std::vector& partitions, - const std::vector& tablet_indexes, const std::vector& skip, - size_t row_cnt) { - for (int row_idx = 0; row_idx < row_cnt; row_idx++) { - if (skip[row_idx]) { - continue; - } - - auto& partition = partitions[row_idx]; - auto& tablet_index = tablet_indexes[row_idx]; +void VOlapTableSinkV2::_generate_rows_for_tablet(std::vector& row_part_tablet_ids, + RowsForTablet& rows_for_tablet) { + for (int index_idx = 0; index_idx < row_part_tablet_ids.size(); index_idx++) { + auto& row_ids = row_part_tablet_ids[index_idx].row_ids; + auto& partition_ids = row_part_tablet_ids[index_idx].partition_ids; + auto& tablet_ids = row_part_tablet_ids[index_idx].tablet_ids; - for (const auto& index : partition->indexes) { - auto tablet_id = index.tablets[tablet_index]; + for (int i = 0; i < row_ids.size(); i++) { + auto& tablet_id = tablet_ids[i]; auto it = rows_for_tablet.find(tablet_id); if (it == rows_for_tablet.end()) { Rows rows; - rows.partition_id = partition->id; - rows.index_id = index.index_id; - rows.row_idxes.reserve(row_cnt); + rows.partition_id = partition_ids[i]; + rows.index_id = _schema->indexes()[index_idx]->index_id; + rows.row_idxes.reserve(row_ids.size()); auto [tmp_it, _] = rows_for_tablet.insert({tablet_id, rows}); it = tmp_it; } - it->second.row_idxes.push_back(row_idx); + it->second.row_idxes.push_back(row_ids[i]); _number_output_rows++; } } @@ -285,37 +319,18 @@ Status VOlapTableSinkV2::send(RuntimeState* state, vectorized::Block* input_bloc DorisMetrics::instance()->load_rows->increment(input_rows); DorisMetrics::instance()->load_bytes->increment(input_bytes); - std::shared_ptr block; bool has_filtered_rows = false; - RETURN_IF_ERROR(_block_convertor->validate_and_convert_block( - state, input_block, block, _output_vexpr_ctxs, input_rows, has_filtered_rows)); - - // clear and release the references of columns - input_block->clear(); + int64_t filtered_rows = 0; SCOPED_RAW_TIMER(&_send_data_ns); // This is just for passing compilation. - bool stop_processing = false; - RowsForTablet rows_for_tablet; - _tablet_finder->clear_for_new_batch(); _row_distribution_watch.start(); - const auto num_rows = input_rows; - const auto* __restrict filter_map = _block_convertor->filter_map(); - //reuse vars - _partitions.assign(num_rows, nullptr); - _skip.assign(num_rows, false); - _tablet_indexes.assign(num_rows, 0); - - RETURN_IF_ERROR(_tablet_finder->find_tablets(_state, block.get(), num_rows, _partitions, - _tablet_indexes, stop_processing, _skip)); - - if (has_filtered_rows) { - for (int i = 0; i < num_rows; i++) { - _skip[i] = _skip[i] || filter_map[i]; - } - } - _generate_rows_for_tablet(rows_for_tablet, _partitions, _tablet_indexes, _skip, num_rows); + std::shared_ptr block; + RETURN_IF_ERROR(_row_distribution.generate_rows_distribution( + *input_block, block, filtered_rows, has_filtered_rows, _row_part_tablet_ids)); + RowsForTablet rows_for_tablet; + _generate_rows_for_tablet(_row_part_tablet_ids, rows_for_tablet); _row_distribution_watch.stop(); diff --git a/be/src/vec/sink/vtablet_sink_v2.h b/be/src/vec/sink/vtablet_sink_v2.h index 63f0985eb090ce..a67c4e65cd2cae 100644 --- a/be/src/vec/sink/vtablet_sink_v2.h +++ b/be/src/vec/sink/vtablet_sink_v2.h @@ -64,6 +64,7 @@ #include "vec/core/block.h" #include "vec/data_types/data_type.h" #include "vec/exprs/vexpr_fwd.h" +#include "vec/sink/vrow_distribution.h" namespace doris { class DeltaWriterV2; @@ -112,17 +113,20 @@ class VOlapTableSinkV2 final : public DataSink { Status open(RuntimeState* state) override; Status close(RuntimeState* state, Status close_status) override; + Status send(RuntimeState* state, vectorized::Block* block, bool eos = false) override; + Status on_partitions_created(TCreatePartitionResult* result); + private: + void _init_row_distribution(); + Status _open_streams(int64_t src_id); void _build_tablet_node_mapping(); - void _generate_rows_for_tablet(RowsForTablet& rows_for_tablet, - const std::vector& partitions, - const std::vector& tablet_indexes, - const std::vector& skip, size_t row_cnt); + void _generate_rows_for_tablet(std::vector& row_part_tablet_ids, + RowsForTablet& rows_for_tablet); Status _write_memtable(std::shared_ptr block, int64_t tablet_id, const Rows& rows, const Streams& streams); @@ -168,11 +172,6 @@ class VOlapTableSinkV2 final : public DataSink { int64_t _number_input_rows = 0; int64_t _number_output_rows = 0; - // reuse for find_tablet - std::vector _partitions; - std::vector _skip; - std::vector _tablet_indexes; - MonotonicStopWatch _row_distribution_watch; RuntimeProfile::Counter* _input_rows_counter = nullptr; @@ -187,6 +186,7 @@ class VOlapTableSinkV2 final : public DataSink { RuntimeProfile::Counter* _close_timer = nullptr; RuntimeProfile::Counter* _close_writer_timer = nullptr; RuntimeProfile::Counter* _close_load_timer = nullptr; + RuntimeProfile::Counter* _add_partition_request_timer = nullptr; // Save the status of close() method Status _close_status; @@ -204,6 +204,10 @@ class VOlapTableSinkV2 final : public DataSink { std::unordered_map> _streams_for_node; size_t _stream_index = 0; std::shared_ptr _delta_writer_for_tablet; + + VRowDistribution _row_distribution; + // reuse to avoid frequent memory allocation and release. + std::vector _row_part_tablet_ids; }; } // namespace vectorized diff --git a/be/src/vec/sink/writer/vtablet_writer.cpp b/be/src/vec/sink/writer/vtablet_writer.cpp index d0720255695b3f..786c0e21105ac9 100644 --- a/be/src/vec/sink/writer/vtablet_writer.cpp +++ b/be/src/vec/sink/writer/vtablet_writer.cpp @@ -152,6 +152,7 @@ Status IndexChannel::init(RuntimeState* state, const std::vectorprepare(state, *_parent->_output_row_desc)); RETURN_IF_ERROR(_where_clause->open(state)); } + return Status::OK(); } @@ -488,52 +489,6 @@ Status VNodeChannel::add_block(vectorized::Block* block, const Payload* payload, _cur_mutable_block = vectorized::MutableBlock::create_unique(block->clone_empty()); } - std::unique_ptr temp_payload = nullptr; - if (_index_channel != nullptr && _index_channel->get_where_clause() != nullptr) { - SCOPED_RAW_TIMER(&_stat.where_clause_ns); - temp_payload.reset(new Payload( - std::unique_ptr(new vectorized::IColumn::Selector()), - std::vector())); - int result_index = -1; - size_t column_number = block->columns(); - RETURN_IF_ERROR(_index_channel->get_where_clause()->execute(block, &result_index)); - - auto& row_ids = *payload->first; - auto& tablets_ids = payload->second; - - auto filter_column = block->get_by_position(result_index).column; - - if (auto* nullable_column = - vectorized::check_and_get_column(*filter_column)) { - for (size_t i = 0; i < payload->second.size(); i++) { - if (nullable_column->get_bool_inline(row_ids[i])) { - temp_payload->first->emplace_back(row_ids[i]); - temp_payload->second.emplace_back(tablets_ids[i]); - } - } - payload = temp_payload.get(); - } else if (auto* const_column = vectorized::check_and_get_column( - *filter_column)) { - bool ret = const_column->get_bool(0); - if (!ret) { - return Status::OK(); - } - } else { - auto& filter = assert_cast(*filter_column).get_data(); - for (size_t i = 0; i < payload->second.size(); i++) { - if (filter[row_ids[i]] != 0) { - temp_payload->first->emplace_back(row_ids[i]); - temp_payload->second.emplace_back(tablets_ids[i]); - } - } - payload = temp_payload.get(); - } - - for (size_t i = block->columns() - 1; i >= column_number; i--) { - block->erase(i); - } - } - SCOPED_RAW_TIMER(&_stat.append_node_channel_ns); if (is_append) { // Do not split the data of the block by tablets but append it to a single delta writer. @@ -1095,6 +1050,43 @@ Status VTabletWriter::open(doris::RuntimeState* state, doris::RuntimeProfile* pr return Status::OK(); } +Status VTabletWriter::on_partitions_created(TCreatePartitionResult* result) { + // add new tablet locations. it will use by address. so add to pool + auto* new_locations = _pool->add(new std::vector(result->tablets)); + _location->add_locations(*new_locations); + + // update new node info + _nodes_info->add_nodes(result->nodes); + + // incremental open node channel + RETURN_IF_ERROR(_incremental_open_node_channel(result->partitions)); + + return Status::OK(); +} + +static Status on_partitions_created(void* writer, TCreatePartitionResult* result) { + return static_cast(writer)->on_partitions_created(result); +} + +void VTabletWriter::_init_row_distribution() { + VRowDistributionContext ctx; + + ctx.state = _state; + ctx.block_convertor = _block_convertor.get(); + ctx.tablet_finder = _tablet_finder.get(); + ctx.vpartition = _vpartition; + ctx.add_partition_request_timer = _add_partition_request_timer; + ctx.txn_id = _txn_id; + ctx.pool = _pool; + ctx.location = _location; + ctx.vec_output_expr_ctxs = &_vec_output_expr_ctxs; + ctx.on_partitions_created = &vectorized::on_partitions_created; + ctx.caller = (void*)this; + ctx.schema = _schema; + + _row_distribution.init(&ctx); +} + Status VTabletWriter::_init(RuntimeState* state, RuntimeProfile* profile) { DCHECK(_t_sink.__isset.olap_table_sink); auto& table_sink = _t_sink.olap_table_sink; @@ -1243,49 +1235,12 @@ Status VTabletWriter::_init(RuntimeState* state, RuntimeProfile* profile) { RETURN_IF_ERROR(_state->exec_env()->wal_mgr()->create_wal_writer(_wal_id, _wal_writer)); } + _init_row_distribution(); + _inited = true; return Status::OK(); } -Status VTabletWriter::_automatic_create_partition() { - SCOPED_TIMER(_add_partition_request_timer); - TCreatePartitionRequest request; - TCreatePartitionResult result; - request.__set_txn_id(_txn_id); - request.__set_db_id(_vpartition->db_id()); - request.__set_table_id(_vpartition->table_id()); - request.__set_partitionValues(_partitions_need_create); - - VLOG(1) << "automatic partition rpc begin request " << request; - TNetworkAddress master_addr = ExecEnv::GetInstance()->master_info()->network_address; - int time_out = _state->execution_timeout() * 1000; - RETURN_IF_ERROR(ThriftRpcHelper::rpc( - master_addr.hostname, master_addr.port, - [&request, &result](FrontendServiceConnection& client) { - client->createPartition(result, request); - }, - time_out)); - - Status status(Status::create(result.status)); - VLOG(1) << "automatic partition rpc end response " << result; - if (result.status.status_code == TStatusCode::OK) { - // add new created partitions - RETURN_IF_ERROR(_vpartition->add_partitions(result.partitions)); - - // add new tablet locations. it will use by address. so add to pool - auto* new_locations = _pool->add(new std::vector(result.tablets)); - _location->add_locations(*new_locations); - - // update new node info - _nodes_info->add_nodes(result.nodes); - - // incremental open node channel - RETURN_IF_ERROR(_incremental_open_node_channel(result.partitions)); - } - - return status; -} - Status VTabletWriter::_incremental_open_node_channel( const std::vector& partitions) { // do what we did in prepare() for partitions. indexes which don't change when we create new partition is orthogonal to partitions. @@ -1337,129 +1292,11 @@ Status VTabletWriter::_incremental_open_node_channel( return Status::OK(); } -// Generate channel payload for sinking data to differenct node channel -// Payload = std::pair, std::vector>; -// first = row_id, second = vector -void VTabletWriter::_generate_row_distribution_payload( - ChannelDistributionPayload& channel_to_payload, - const std::vector& partitions, - const std::vector& tablet_indexes, const std::vector& skip, - size_t row_cnt) { - for (int row_idx = 0; row_idx < row_cnt; row_idx++) { - if (skip[row_idx]) { - continue; - } - const auto& partition = partitions[row_idx]; - const auto& tablet_index = tablet_indexes[row_idx]; - - for (int index_num = 0; index_num < partition->indexes.size(); - ++index_num) { // partition->indexes = [index, tablets...] - - auto tablet_id = partition->indexes[index_num].tablets[tablet_index]; - auto it = _channels[index_num]->_channels_by_tablet.find( - tablet_id); // (tablet_id, VNodeChannel) where this tablet locate - - DCHECK(it != _channels[index_num]->_channels_by_tablet.end()) - << "unknown tablet, tablet_id=" << tablet_index; - - std::vector>& tablet_locations = it->second; - std::unordered_map& payloads_this_index = - channel_to_payload[index_num]; // payloads of this index in every node - - for (const auto& locate_node : tablet_locations) { - auto payload_it = - payloads_this_index.find(locate_node.get()); // - if (payload_it == payloads_this_index.end()) { - auto [tmp_it, _] = payloads_this_index.emplace( - locate_node.get(), - Payload {std::make_unique(), - std::vector()}); - payload_it = tmp_it; - payload_it->second.first->reserve(row_cnt); - payload_it->second.second.reserve(row_cnt); - } - payload_it->second.first->push_back(row_idx); - payload_it->second.second.push_back(tablet_id); - } - _number_output_rows++; - } - } -} - -Status VTabletWriter::_single_partition_generate(RuntimeState* state, vectorized::Block* block, - ChannelDistributionPayload& channel_to_payload, - size_t num_rows, bool has_filtered_rows) { - // only need to calculate one value for single partition. - std::vector partitions(1, nullptr); - std::vector skip(1, false); - std::vector tablet_indexes(1, 0); - bool stop_processing = false; - - RETURN_IF_ERROR(_tablet_finder->find_tablets(_state, block, 1, partitions, tablet_indexes, - stop_processing, skip)); - - const VOlapTablePartition* partition = nullptr; - uint32_t tablet_index = 0; - for (size_t i = 0; i < num_rows; i++) { - if (!skip[i]) { - partition = partitions[i]; - tablet_index = tablet_indexes[i]; - break; - } - } - if (partition == nullptr) { - return Status::OK(); - } - - for (int j = 0; j < partition->indexes.size(); ++j) { - auto tid = partition->indexes[j].tablets[tablet_index]; - auto it = _channels[j]->_channels_by_tablet.find(tid); - DCHECK(it != _channels[j]->_channels_by_tablet.end()) - << "unknown tablet, tablet_id=" << tablet_index; - int64_t row_cnt = 0; - for (const auto& channel : it->second) { - if (!channel_to_payload[j].contains(channel.get())) { - channel_to_payload[j].insert( - {channel.get(), Payload {std::make_unique(), - std::vector()}}); - } - auto& selector = channel_to_payload[j][channel.get()].first; - auto& tablet_ids = channel_to_payload[j][channel.get()].second; - for (int32_t i = 0; i < num_rows; ++i) { - if (UNLIKELY(has_filtered_rows) && _block_convertor->filter_map()[i]) { - continue; - } - selector->push_back(i); - } - tablet_ids.resize(selector->size(), tid); - row_cnt = selector->size(); - } - _number_output_rows += row_cnt; - } - return Status::OK(); -} - std::pair VTabletWriter::_get_partition_function() { return {_vpartition->get_part_func_ctx(), _vpartition->get_partition_function()}; } -void VTabletWriter::_save_missing_values(vectorized::ColumnPtr col, - vectorized::DataTypePtr value_type, - std::vector filter) { - _partitions_need_create.clear(); - std::set deduper; - // de-duplication - for (auto row : filter) { - deduper.emplace(value_type->to_string(*col, row)); - } - for (auto& value : deduper) { - TStringLiteral node; - node.value = value; - _partitions_need_create.emplace_back(std::vector {node}); // only 1 partition column now - } -} - Status VTabletWriter::_cancel_channel_and_check_intolerable_failure( Status status, const std::string& err_msg, const std::shared_ptr ich, const std::shared_ptr nch) { @@ -1705,6 +1542,46 @@ Status VTabletWriter::close(Status exec_status) { return _close_status; } +void VTabletWriter::_generate_one_index_channel_payload( + RowPartTabletIds& row_part_tablet_id, int32_t index_idx, + ChannelDistributionPayload& channel_payload) { + auto& row_ids = row_part_tablet_id.row_ids; + auto& tablet_ids = row_part_tablet_id.tablet_ids; + + size_t row_cnt = row_ids.size(); + + for (int i = 0; i < row_ids.size(); i++) { + // (tablet_id, VNodeChannel) where this tablet locate + auto it = _channels[index_idx]->_channels_by_tablet.find(tablet_ids[i]); + DCHECK(it != _channels[index_idx]->_channels_by_tablet.end()) + << "unknown tablet, tablet_id=" << tablet_ids[i]; + + std::vector>& tablet_locations = it->second; + for (const auto& locate_node : tablet_locations) { + auto payload_it = channel_payload.find(locate_node.get()); // + if (payload_it == channel_payload.end()) { + auto [tmp_it, _] = channel_payload.emplace( + locate_node.get(), + Payload {std::make_unique(), + std::vector()}); + payload_it = tmp_it; + payload_it->second.first->reserve(row_cnt); + payload_it->second.second.reserve(row_cnt); + } + payload_it->second.first->push_back(row_ids[i]); + payload_it->second.second.push_back(tablet_ids[i]); + } + } +} + +void VTabletWriter::_generate_index_channels_payloads( + std::vector& row_part_tablet_ids, + ChannelDistributionPayloadVec& payload) { + for (int i = 0; i < _schema->indexes().size(); i++) { + _generate_one_index_channel_payload(row_part_tablet_ids[i], i, payload[i]); + } +} + Status VTabletWriter::append_block(doris::vectorized::Block& input_block) { SCOPED_CONSUME_MEM_TRACKER(_mem_tracker.get()); Status status = Status::OK(); @@ -1719,6 +1596,19 @@ Status VTabletWriter::append_block(doris::vectorized::Block& input_block) { return status; } SCOPED_TIMER(_profile->total_time_counter()); + + std::shared_ptr block; + bool has_filtered_rows = false; + int64_t filtered_rows = 0; + + RETURN_IF_ERROR(_row_distribution.generate_rows_distribution( + input_block, block, filtered_rows, has_filtered_rows, _row_part_tablet_ids)); + + ChannelDistributionPayloadVec channel_to_payload; + + channel_to_payload.resize(_channels.size()); + _generate_index_channels_payloads(_row_part_tablet_ids, channel_to_payload); + _number_input_rows += rows; // update incrementally so that FE can get the progress. // the real 'num_rows_load_total' will be set when sink being closed. @@ -1727,112 +1617,6 @@ Status VTabletWriter::append_block(doris::vectorized::Block& input_block) { DorisMetrics::instance()->load_rows->increment(rows); DorisMetrics::instance()->load_bytes->increment(bytes); - std::shared_ptr block; - bool has_filtered_rows = false; - int64_t filtered_rows = - _block_convertor->num_filtered_rows() + _tablet_finder->num_filtered_rows(); - RETURN_IF_ERROR(_block_convertor->validate_and_convert_block( - _state, &input_block, block, _vec_output_expr_ctxs, rows, has_filtered_rows)); - - SCOPED_RAW_TIMER(&_send_data_ns); - // This is just for passing compilation. - bool stop_processing = false; - ChannelDistributionPayload channel_to_payload; - channel_to_payload.resize(_channels.size()); - _tablet_finder->clear_for_new_batch(); - _row_distribution_watch.start(); - auto num_rows = block->rows(); - _tablet_finder->filter_bitmap().Reset(num_rows); - size_t partition_num = _vpartition->get_partitions().size(); - if (!_vpartition->is_auto_partition() && partition_num == 1 && - _tablet_finder->is_find_tablet_every_sink()) { - RETURN_IF_ERROR(_single_partition_generate(_state, block.get(), channel_to_payload, - num_rows, has_filtered_rows)); - } else { - // if there's projection of partition calc, we need to calc it first. - auto [part_ctx, part_func] = _get_partition_function(); - int result_idx = -1; - if (_vpartition->is_projection_partition()) { - // calc the start value of missing partition ranges. - RETURN_IF_ERROR(part_func->execute(part_ctx.get(), block.get(), &result_idx)); - VLOG_DEBUG << "Partition-calculated block:" << block->dump_data(); - // change the column to compare to transformed. - _vpartition->set_transformed_slots({(uint16_t)result_idx}); - } - - if (_vpartition->is_auto_partition()) { - std::vector partition_keys = _vpartition->get_partition_keys(); - //TODO: use loop to create missing_vals for multi column. - CHECK(partition_keys.size() == 1) - << "now support only 1 partition column for auto partitions."; - auto partition_col = block->get_by_position(partition_keys[0]); - - std::vector missing_map; // indice of missing values in partition_col - missing_map.reserve(partition_col.column->size()); - - // try to find tablet and save missing value - std::vector partitions(num_rows, nullptr); - std::vector skip(num_rows, false); - std::vector tablet_indexes(num_rows, 0); - - //TODO: we could use the buffer to save tablets we found so that no need to find them again when we created partitions and try to append block next time. - RETURN_IF_ERROR(_tablet_finder->find_tablets(_state, block.get(), num_rows, partitions, - tablet_indexes, stop_processing, skip, - &missing_map)); - - if (missing_map.empty()) { - // we don't calculate it distribution when have missing values - if (has_filtered_rows) { - for (int i = 0; i < num_rows; i++) { - skip[i] = skip[i] || _block_convertor->filter_map()[i]; - } - } - _generate_row_distribution_payload(channel_to_payload, partitions, tablet_indexes, - skip, num_rows); - } else { // for missing partition keys, calc the missing partition and save in _partitions_need_create - auto return_type = part_func->data_type(); - - // expose the data column - vectorized::ColumnPtr range_left_col = block->get_by_position(result_idx).column; - if (const auto* nullable = - check_and_get_column(*range_left_col)) { - range_left_col = nullable->get_nested_column_ptr(); - return_type = - assert_cast(return_type.get()) - ->get_nested_type(); - } - // calc the end value and save them. - _save_missing_values(range_left_col, return_type, missing_map); - // then call FE to create it. then FragmentExecutor will redo the load. - RETURN_IF_ERROR(_automatic_create_partition()); - // now we need to rollback the metrics - _number_input_rows -= rows; - _state->update_num_rows_load_total(-rows); - _state->update_num_bytes_load_total(-bytes); - DorisMetrics::instance()->load_rows->increment(-rows); - DorisMetrics::instance()->load_bytes->increment(-bytes); - // In the next round, we will _generate_row_distribution_payload again to get right payload of new tablet - LOG(INFO) << "Auto created partition. Send block again."; - return Status::NeedSendAgain(""); - } // creating done - } else { // not auto partition - std::vector partitions(num_rows, nullptr); - std::vector skip(num_rows, false); - std::vector tablet_indexes(num_rows, 0); - - RETURN_IF_ERROR(_tablet_finder->find_tablets(_state, block.get(), num_rows, partitions, - tablet_indexes, stop_processing, skip)); - - if (has_filtered_rows) { - for (int i = 0; i < num_rows; i++) { - skip[i] = skip[i] || _block_convertor->filter_map()[i]; - } - } - _generate_row_distribution_payload(channel_to_payload, partitions, tablet_indexes, skip, - num_rows); - } - } - _row_distribution_watch.stop(); // Random distribution and the block belongs to a single tablet, we could optimize to append the whole // block into node channel. bool load_block_to_single_tablet = @@ -1855,10 +1639,8 @@ Status VTabletWriter::append_block(doris::vectorized::Block& input_block) { } if (_group_commit) { - _group_commit_block(&input_block, num_rows, - _block_convertor->num_filtered_rows() + - _tablet_finder->num_filtered_rows() - filtered_rows, - _state, block.get(), _block_convertor.get(), _tablet_finder.get()); + _group_commit_block(&input_block, block->rows(), filtered_rows, _state, block.get(), + _block_convertor.get(), _tablet_finder.get()); } // TODO: Before load, we need to projection unuseful column // auto slots = _schema->tuple_desc()->slots(); diff --git a/be/src/vec/sink/writer/vtablet_writer.h b/be/src/vec/sink/writer/vtablet_writer.h index c8d5d1c2ce9ae9..7fee45be371080 100644 --- a/be/src/vec/sink/writer/vtablet_writer.h +++ b/be/src/vec/sink/writer/vtablet_writer.h @@ -74,6 +74,7 @@ #include "vec/data_types/data_type.h" #include "vec/exprs/vexpr_fwd.h" #include "vec/runtime/vfile_format_transformer.h" +#include "vec/sink/vrow_distribution.h" #include "vec/sink/vtablet_block_convertor.h" #include "vec/sink/vtablet_finder.h" #include "vec/sink/writer/async_result_writer.h" @@ -204,9 +205,6 @@ class ReusableClosure final : public google::protobuf::Closure { class IndexChannel; class VTabletWriter; -// pair -using Payload = std::pair, std::vector>; - class VNodeChannelStat { public: VNodeChannelStat& operator+=(const VNodeChannelStat& stat) { @@ -221,6 +219,9 @@ class VNodeChannelStat { int64_t append_node_channel_ns = 0; }; +// pair +using Payload = std::pair, std::vector>; + // every NodeChannel keeps a data transmission channel with one BE. for multiple times open, it has a dozen of requests and corresponding closures. class VNodeChannel { public: @@ -485,6 +486,7 @@ class IndexChannel { private: friend class VNodeChannel; friend class VTabletWriter; + friend class VRowDistribution; VTabletWriter* _parent; int64_t _index_id; @@ -546,32 +548,34 @@ class VTabletWriter final : public AsyncResultWriter { bool is_close_done(); + Status on_partitions_created(TCreatePartitionResult* result); + private: friend class VNodeChannel; friend class IndexChannel; - using ChannelDistributionPayload = std::vector>; + using ChannelDistributionPayload = std::unordered_map; + using ChannelDistributionPayloadVec = std::vector>; + + void _init_row_distribution(); Status _init(RuntimeState* state, RuntimeProfile* profile); - // payload for every row - void _generate_row_distribution_payload(ChannelDistributionPayload& channel_to_payload, - const std::vector& partitions, - const std::vector& tablet_indexes, - const std::vector& skip, size_t row_cnt); + void _generate_one_index_channel_payload(RowPartTabletIds& row_part_tablet_tuple, + int32_t index_idx, + ChannelDistributionPayload& channel_payload); - Status _single_partition_generate(RuntimeState* state, vectorized::Block* block, - ChannelDistributionPayload& channel_to_payload, - size_t num_rows, bool has_filtered_rows); + void _generate_index_channels_payloads(std::vector& row_part_tablet_ids, + ChannelDistributionPayloadVec& payload); Status _cancel_channel_and_check_intolerable_failure(Status status, const std::string& err_msg, const std::shared_ptr ich, const std::shared_ptr nch); - void _cancel_all_channel(Status status); - std::pair _get_partition_function(); + void _cancel_all_channel(Status status); + void _save_missing_values(vectorized::ColumnPtr col, vectorized::DataTypePtr value_type, std::vector filter); @@ -689,6 +693,11 @@ class VTabletWriter final : public AsyncResultWriter { RuntimeProfile* _profile = nullptr; // not owned, set when open bool _group_commit = false; std::shared_ptr _wal_writer = nullptr; + + VRowDistribution _row_distribution; + // reuse to avoid frequent memory allocation and release. + std::vector _row_part_tablet_ids; + int64_t _tb_id; int64_t _db_id; int64_t _wal_id; From f8f3bc6a6701fad5d2e94fc6d54c7ded4b8912c9 Mon Sep 17 00:00:00 2001 From: Calvin Kirs Date: Wed, 8 Nov 2023 11:52:08 +0800 Subject: [PATCH 36/88] Revert "[Chore](ci)Temporarily cancel the mandatory restrictions of ShellCheck (#26553)" (#26565) This reverts commit b7c81bc73625b26df746fc2213980c16b9d8f1a0. --- .asf.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.asf.yaml b/.asf.yaml index 59f6fd20e75068..f8b7e0913cf61b 100644 --- a/.asf.yaml +++ b/.asf.yaml @@ -59,6 +59,7 @@ github: - BE UT (Doris BE UT) - Build Broker - Build Documents + - ShellCheck - clickbench-new (clickbench) - Build Third Party Libraries (Linux) - Build Third Party Libraries (macOS) From 9502cc758d0fcecaa51ba3ccc264cbce83aaf1d9 Mon Sep 17 00:00:00 2001 From: meiyi Date: Wed, 8 Nov 2023 11:57:07 +0800 Subject: [PATCH 37/88] [fix](regression) fix group commit regression test (#26557) --- be/src/service/internal_service.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/be/src/service/internal_service.cpp b/be/src/service/internal_service.cpp index 52b448a5f6db92..01151dcf340b99 100644 --- a/be/src/service/internal_service.cpp +++ b/be/src/service/internal_service.cpp @@ -1849,9 +1849,10 @@ void PInternalServiceImpl::group_commit_insert(google::protobuf::RpcController* } } st.to_protobuf(response->mutable_status()); + _exec_env->new_load_stream_mgr()->remove(load_id); }); - _exec_env->new_load_stream_mgr()->remove(load_id); if (!ret) { + _exec_env->new_load_stream_mgr()->remove(load_id); offer_failed(response, done, _light_work_pool); return; } From 0f3e97f9c5b8d655544c8cc335ec3fbf0b0535ee Mon Sep 17 00:00:00 2001 From: shuke <37901441+shuke987@users.noreply.github.com> Date: Wed, 8 Nov 2023 12:46:36 +0800 Subject: [PATCH 38/88] [regression-test][framework] support cases that can only run in non-concurrent-mode. (#26487) --- .../doris/regression/RegressionTest.groovy | 59 +++++++++++++++++-- .../pipeline/p0/conf/regression-conf.groovy | 2 +- .../pipeline/p1/conf/regression-conf.groovy | 2 +- .../test_index_fault_injection.groovy | 2 +- .../test_segcompaction_fault_injection.groovy | 2 +- ...t_too_many_segments_fault_injection.groovy | 2 +- .../test_sql_block_rule.groovy | 2 +- 7 files changed, 59 insertions(+), 12 deletions(-) diff --git a/regression-test/framework/src/main/groovy/org/apache/doris/regression/RegressionTest.groovy b/regression-test/framework/src/main/groovy/org/apache/doris/regression/RegressionTest.groovy index 4e7a5793aa55f2..6cdb918a7f4666 100644 --- a/regression-test/framework/src/main/groovy/org/apache/doris/regression/RegressionTest.groovy +++ b/regression-test/framework/src/main/groovy/org/apache/doris/regression/RegressionTest.groovy @@ -50,9 +50,11 @@ class RegressionTest { static GroovyShell shell static ExecutorService scriptExecutors static ExecutorService suiteExecutors + static ExecutorService singleSuiteExecutors static ExecutorService actionExecutors static ThreadLocal threadLoadedClassNum = new ThreadLocal<>() static final int cleanLoadedClassesThreshold = 20 + static String nonConcurrentTestGroup = "nonConcurrent" static void main(String[] args) { CommandLine cmd = ConfigOptions.initCommands(args) @@ -70,6 +72,7 @@ class RegressionTest { } actionExecutors.shutdown() suiteExecutors.shutdown() + singleSuiteExecutors.shutdown() scriptExecutors.shutdown() log.info("Test finished") if (!success) { @@ -96,6 +99,12 @@ class RegressionTest { .build(); suiteExecutors = Executors.newFixedThreadPool(config.suiteParallel, suiteFactory) + BasicThreadFactory singleSuiteFactory = new BasicThreadFactory.Builder() + .namingPattern("non-concurrent-thread-%d") + .priority(Thread.MAX_PRIORITY) + .build(); + singleSuiteExecutors = Executors.newFixedThreadPool(1, singleSuiteFactory) + BasicThreadFactory actionFactory = new BasicThreadFactory.Builder() .namingPattern("action-thread-%d") .priority(Thread.MAX_PRIORITY) @@ -131,9 +140,9 @@ class RegressionTest { return sources } - static void runScript(Config config, ScriptSource source, Recorder recorder) { + static void runScript(Config config, ScriptSource source, Recorder recorder, boolean isSingleThreadScript) { def suiteFilter = { String suiteName, String groupName -> - canRun(config, suiteName, groupName) + canRun(config, suiteName, groupName, isSingleThreadScript) } def file = source.getFile() int failureLimit = Integer.valueOf(config.otherConfigs.getOrDefault("max_failure_num", "-1").toString()); @@ -144,7 +153,14 @@ class RegressionTest { return; } def eventListeners = getEventListeners(config, recorder) - new ScriptContext(file, suiteExecutors, actionExecutors, + ExecutorService executors = null + if (isSingleThreadScript) { + executors = singleSuiteExecutors + } else { + executors = suiteExecutors + } + + new ScriptContext(file, executors, actionExecutors, config, eventListeners, suiteFilter).start { scriptContext -> try { SuiteScript suiteScript = source.toScript(scriptContext, shell) @@ -168,7 +184,26 @@ class RegressionTest { scriptSources.eachWithIndex { source, i -> // log.info("Prepare scripts [${i + 1}/${totalFile}]".toString()) def future = scriptExecutors.submit { - runScript(config, source, recorder) + runScript(config, source, recorder, false) + } + futures.add(future) + } + + // wait all scripts + for (Future future : futures) { + try { + future.get() + } catch (Throwable t) { + // do nothing, because already save to Recorder + } + } + + log.info('Start to run single scripts') + futures.clear() + scriptSources.eachWithIndex { source, i -> +// log.info("Prepare scripts [${i + 1}/${totalFile}]".toString()) + def future = scriptExecutors.submit { + runScript(config, source, recorder, true) } futures.add(future) } @@ -192,8 +227,9 @@ class RegressionTest { { fileName -> fileName.substring(0, fileName.lastIndexOf(".")) == "load" }) } log.info('Start to run scripts') - runScripts(config, recorder, directoryFilter, + runScripts(config, recorder, directoryFilter, { fileName -> fileName.substring(0, fileName.lastIndexOf(".")) != "load" }) + return recorder } @@ -228,7 +264,18 @@ class RegressionTest { return true } - static boolean canRun(Config config, String suiteName, String group) { + static boolean canRun(Config config, String suiteName, String group, boolean isSingleThreadScript) { + Set suiteGroups = group.split(',').collect { g -> g.trim() }.toSet(); + if (isSingleThreadScript) { + if (!suiteGroups.contains(nonConcurrentTestGroup)) { + return false + } + } else { + if (suiteGroups.contains(nonConcurrentTestGroup)) { + return false + } + } + return filterGroups(config, group) && filterSuites(config, suiteName) } diff --git a/regression-test/pipeline/p0/conf/regression-conf.groovy b/regression-test/pipeline/p0/conf/regression-conf.groovy index 364a7103fe8612..67e014f63a6768 100644 --- a/regression-test/pipeline/p0/conf/regression-conf.groovy +++ b/regression-test/pipeline/p0/conf/regression-conf.groovy @@ -55,7 +55,7 @@ testDirectories = "" excludeGroups = "" // this suites will not be executed -excludeSuites = "test_sql_block_rule,test_profile,test_spark_load,test_refresh_mtmv,test_bitmap_filter,test_jdbc_query_mysql" +excludeSuites = "test_profile,test_spark_load,test_refresh_mtmv,test_bitmap_filter,test_jdbc_query_mysql" // this directories will not be executed excludeDirectories = "workload_manager_p1,fault_injection_p0" diff --git a/regression-test/pipeline/p1/conf/regression-conf.groovy b/regression-test/pipeline/p1/conf/regression-conf.groovy index c7040561d5c751..b7eec21a41f324 100644 --- a/regression-test/pipeline/p1/conf/regression-conf.groovy +++ b/regression-test/pipeline/p1/conf/regression-conf.groovy @@ -49,7 +49,7 @@ testSuites = "" // this suites will not be executed excludeSuites = "test_big_pad,test_profile,test_broker_load,test_spark_load,test_analyze_stats_p1,test_refresh_mtmv,test_bitmap_filter" // this dir will not be executed -excludeDirectories = "workload_manager_p1" +excludeDirectories = "workload_manager_p1,fault_injection_p0" cacheDataPath="/data/regression/" s3Endpoint = "cos.ap-hongkong.myqcloud.com" diff --git a/regression-test/suites/fault_injection_p0/test_index_fault_injection.groovy b/regression-test/suites/fault_injection_p0/test_index_fault_injection.groovy index 93860b46bbc643..b3f6c24d60a644 100644 --- a/regression-test/suites/fault_injection_p0/test_index_fault_injection.groovy +++ b/regression-test/suites/fault_injection_p0/test_index_fault_injection.groovy @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -suite("test_index_failure_injection", "p0") { +suite("test_index_failure_injection", "p0", "nonConcurrent") { // define a sql table def testTable_dup = "httplogs_dup" def testTable_unique = "httplogs_unique" diff --git a/regression-test/suites/fault_injection_p0/test_segcompaction_fault_injection.groovy b/regression-test/suites/fault_injection_p0/test_segcompaction_fault_injection.groovy index 2f601f13d11959..a4ded1a58e0f3d 100644 --- a/regression-test/suites/fault_injection_p0/test_segcompaction_fault_injection.groovy +++ b/regression-test/suites/fault_injection_p0/test_segcompaction_fault_injection.groovy @@ -37,7 +37,7 @@ def create_table_sql = """ """ def columns = "col_0, col_1, col_2, col_3, col_4, col_5, col_6, col_7, col_8, col_9, col_10, col_11, col_12, col_13, col_14, col_15, col_16, col_17, col_18, col_19, col_20, col_21, col_22, col_23, col_24, col_25, col_26, col_27, col_28, col_29, col_30, col_31, col_32, col_33, col_34, col_35, col_36, col_37, col_38, col_39, col_40, col_41, col_42, col_43, col_44, col_45, col_46, col_47, col_48, col_49" -suite("test_segcompaction_correctness") { +suite("test_segcompaction_correctness", "nonConcurrent") { def runLoadWithSegcompaction = { String ak = getS3AK() String sk = getS3SK() diff --git a/regression-test/suites/fault_injection_p0/test_too_many_segments_fault_injection.groovy b/regression-test/suites/fault_injection_p0/test_too_many_segments_fault_injection.groovy index b68e324ee98ea3..de7bcac5f10348 100644 --- a/regression-test/suites/fault_injection_p0/test_too_many_segments_fault_injection.groovy +++ b/regression-test/suites/fault_injection_p0/test_too_many_segments_fault_injection.groovy @@ -37,7 +37,7 @@ def create_table_sql = """ """ def columns = "col_0, col_1, col_2, col_3, col_4, col_5, col_6, col_7, col_8, col_9, col_10, col_11, col_12, col_13, col_14, col_15, col_16, col_17, col_18, col_19, col_20, col_21, col_22, col_23, col_24, col_25, col_26, col_27, col_28, col_29, col_30, col_31, col_32, col_33, col_34, col_35, col_36, col_37, col_38, col_39, col_40, col_41, col_42, col_43, col_44, col_45, col_46, col_47, col_48, col_49" -suite("test_too_many_segments") { // the epic -238 case +suite("test_too_many_segments", "nonConcurrent") { // the epic -238 case def runLoadWithTooManySegments = { String ak = getS3AK() String sk = getS3SK() diff --git a/regression-test/suites/sql_block_rule_p0/test_sql_block_rule.groovy b/regression-test/suites/sql_block_rule_p0/test_sql_block_rule.groovy index bc5597dd5a9b9a..53ea9a87d4eb42 100644 --- a/regression-test/suites/sql_block_rule_p0/test_sql_block_rule.groovy +++ b/regression-test/suites/sql_block_rule_p0/test_sql_block_rule.groovy @@ -15,7 +15,7 @@ // specific language governing permissions and limitations // under the License. -suite("test_sql_block_rule") { +suite("test_sql_block_rule", "nonConcurrent") { sql """ DROP SQL_BLOCK_RULE if exists test_rule_partition From 44b51bf0b9ed2dfbc44762628fc38d530c074204 Mon Sep 17 00:00:00 2001 From: lihangyu <15605149486@163.com> Date: Wed, 8 Nov 2023 14:37:57 +0800 Subject: [PATCH 39/88] [Feature](Variant) support variant load (#26572) --- be/src/common/config.cpp | 5 +- be/src/common/config.h | 8 +- be/src/exprs/json_functions.cpp | 31 + be/src/exprs/json_functions.h | 7 + be/src/olap/base_tablet.cpp | 11 + be/src/olap/base_tablet.h | 2 + be/src/olap/compaction.cpp | 3 +- be/src/olap/reader.cpp | 2 +- be/src/olap/rowset/beta_rowset_writer.cpp | 140 ++- be/src/olap/rowset/beta_rowset_writer.h | 10 + be/src/olap/rowset/beta_rowset_writer_v2.h | 2 + be/src/olap/rowset/rowset_writer.h | 1 + be/src/olap/rowset/rowset_writer_context.h | 9 +- .../olap/rowset/segment_v2/column_writer.cpp | 7 + .../olap/rowset/segment_v2/encoding_info.cpp | 4 + .../olap/rowset/segment_v2/segment_writer.cpp | 71 +- .../olap/rowset/vertical_beta_rowset_writer.h | 2 + be/src/olap/rowset_builder.cpp | 9 + be/src/olap/tablet.cpp | 19 +- be/src/olap/tablet.h | 2 +- be/src/olap/tablet_meta.cpp | 3 +- be/src/udf/udf.cpp | 2 + be/src/udf/udf.h | 19 + be/src/util/jsonb_document.h | 18 +- ...gregate_function_approx_count_distinct.cpp | 1 + .../aggregate_function_reader_first_last.h | 1 + be/src/vec/columns/column.h | 22 +- be/src/vec/columns/column_array.cpp | 4 + be/src/vec/columns/column_array.h | 3 +- be/src/vec/columns/column_complex.h | 2 - be/src/vec/columns/column_decimal.h | 1 - be/src/vec/columns/column_dictionary.h | 7 +- be/src/vec/columns/column_dummy.h | 175 +++ .../vec/columns/column_fixed_length_object.h | 2 - be/src/vec/columns/column_impl.h | 29 + be/src/vec/columns/column_map.h | 2 - be/src/vec/columns/column_nothing.h | 44 + be/src/vec/columns/column_nullable.cpp | 8 +- be/src/vec/columns/column_nullable.h | 5 + be/src/vec/columns/column_object.cpp | 1080 ++++++++++++----- be/src/vec/columns/column_object.h | 136 ++- be/src/vec/columns/column_set.h | 50 + be/src/vec/columns/column_string.cpp | 13 + be/src/vec/columns/column_string.h | 27 +- be/src/vec/columns/column_struct.h | 1 - be/src/vec/columns/column_vector.h | 6 +- be/src/vec/columns/predicate_column.h | 9 +- be/src/vec/columns/subcolumn_tree.h | 64 +- be/src/vec/common/field_visitors.h | 2 + be/src/vec/common/schema_util.cpp | 350 ++++-- be/src/vec/common/schema_util.h | 85 +- be/src/vec/core/field.h | 69 +- .../vec/data_types/convert_field_to_type.cpp | 119 +- be/src/vec/data_types/data_type.h | 5 +- be/src/vec/data_types/data_type_agg_state.h | 4 + be/src/vec/data_types/data_type_array.h | 6 +- be/src/vec/data_types/data_type_bitmap.h | 6 +- be/src/vec/data_types/data_type_date.h | 6 +- be/src/vec/data_types/data_type_date_time.h | 4 +- be/src/vec/data_types/data_type_decimal.h | 14 +- .../data_type_fixed_length_object.h | 4 + be/src/vec/data_types/data_type_hll.h | 6 +- be/src/vec/data_types/data_type_ipv4.h | 2 - be/src/vec/data_types/data_type_ipv6.h | 2 - be/src/vec/data_types/data_type_jsonb.h | 5 +- be/src/vec/data_types/data_type_map.h | 6 +- be/src/vec/data_types/data_type_nothing.cpp | 4 +- be/src/vec/data_types/data_type_nothing.h | 5 +- be/src/vec/data_types/data_type_nullable.cpp | 4 - be/src/vec/data_types/data_type_nullable.h | 4 + be/src/vec/data_types/data_type_number.h | 1 - be/src/vec/data_types/data_type_number_base.h | 26 + be/src/vec/data_types/data_type_object.cpp | 28 +- be/src/vec/data_types/data_type_object.h | 28 +- .../vec/data_types/data_type_quantilestate.h | 5 +- be/src/vec/data_types/data_type_string.h | 4 +- be/src/vec/data_types/data_type_struct.h | 4 +- be/src/vec/data_types/data_type_time.h | 5 +- be/src/vec/data_types/data_type_time_v2.h | 10 +- be/src/vec/data_types/get_least_supertype.cpp | 271 +++-- be/src/vec/data_types/get_least_supertype.h | 15 +- .../serde/data_type_array_serde.cpp | 29 + .../data_types/serde/data_type_array_serde.h | 5 + .../serde/data_type_jsonb_serde.cpp | 109 ++ .../data_types/serde/data_type_jsonb_serde.h | 4 + .../serde/data_type_nullable_serde.cpp | 25 + .../serde/data_type_nullable_serde.h | 5 + .../data_types/serde/data_type_number_serde.h | 59 + .../serde/data_type_object_serde.cpp | 48 +- .../data_types/serde/data_type_object_serde.h | 8 +- .../vec/data_types/serde/data_type_serde.cpp | 52 + be/src/vec/data_types/serde/data_type_serde.h | 13 + .../serde/data_type_string_serde.cpp | 24 + .../data_types/serde/data_type_string_serde.h | 4 + .../vec/exec/format/json/new_json_reader.cpp | 21 +- be/src/vec/exec/format/json/new_json_reader.h | 3 +- be/src/vec/functions/function.h | 1 + be/src/vec/functions/function_case.h | 2 + be/src/vec/functions/function_cast.h | 269 +++- be/src/vec/json/json_parser.cpp | 115 +- be/src/vec/json/json_parser.h | 43 +- be/src/vec/json/parse2column.cpp | 101 +- be/src/vec/json/parse2column.h | 9 +- be/src/vec/olap/olap_data_convertor.cpp | 74 +- be/src/vec/olap/olap_data_convertor.h | 19 + 105 files changed, 3174 insertions(+), 1056 deletions(-) create mode 100644 be/src/vec/columns/column_dummy.h create mode 100644 be/src/vec/columns/column_nothing.h create mode 100644 be/src/vec/columns/column_set.h diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp index 8c57e9c8b712b5..e858a5b6acb63f 100644 --- a/be/src/common/config.cpp +++ b/be/src/common/config.cpp @@ -969,6 +969,9 @@ DEFINE_Bool(enable_workload_group_for_scan, "false"); // Will remove after fully test. DEFINE_Bool(enable_index_apply_preds_except_leafnode_of_andnode, "true"); +DEFINE_mBool(enable_flatten_nested_for_variant, "false"); +DEFINE_mDouble(ratio_of_defaults_as_sparse_column, "0.95"); + // block file cache DEFINE_Bool(enable_file_cache, "false"); // format: [{"path":"/path/to/file_cache","total_size":21474836480,"query_limit":10737418240}] @@ -1013,8 +1016,6 @@ DEFINE_Int32(max_depth_in_bkd_tree, "32"); DEFINE_Bool(inverted_index_compaction_enable, "false"); // use num_broadcast_buffer blocks as buffer to do broadcast DEFINE_Int32(num_broadcast_buffer, "32"); -// semi-structure configs -DEFINE_Bool(enable_parse_multi_dimession_array, "false"); // max depth of expression tree allowed. DEFINE_Int32(max_depth_of_expr_tree, "600"); diff --git a/be/src/common/config.h b/be/src/common/config.h index e23fa5c357bf66..b6f8d2c2fb20bb 100644 --- a/be/src/common/config.h +++ b/be/src/common/config.h @@ -1055,8 +1055,6 @@ DECLARE_Int32(max_depth_in_bkd_tree); DECLARE_Bool(inverted_index_compaction_enable); // use num_broadcast_buffer blocks as buffer to do broadcast DECLARE_Int32(num_broadcast_buffer); -// semi-structure configs -DECLARE_Bool(enable_parse_multi_dimession_array); // max depth of expression tree allowed. DECLARE_Int32(max_depth_of_expr_tree); @@ -1134,6 +1132,12 @@ DECLARE_mInt64(lookup_connection_cache_bytes_limit); // level of compression when using LZ4_HC, whose defalut value is LZ4HC_CLEVEL_DEFAULT DECLARE_mInt64(LZ4_HC_compression_level); +// Whether flatten nested arrays in variant column +// Notice: TEST ONLY +DECLARE_mBool(enable_flatten_nested_for_variant); +// Threshold of a column as sparse column +// Notice: TEST ONLY +DECLARE_mDouble(ratio_of_defaults_as_sparse_column); DECLARE_mBool(enable_merge_on_write_correctness_check); diff --git a/be/src/exprs/json_functions.cpp b/be/src/exprs/json_functions.cpp index 30608adeb2546a..fe97d8344c8b68 100644 --- a/be/src/exprs/json_functions.cpp +++ b/be/src/exprs/json_functions.cpp @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include // IWYU pragma: keep #include @@ -316,4 +318,33 @@ Status JsonFunctions::extract_from_object(simdjson::ondemand::object& obj, return Status::OK(); } +std::string JsonFunctions::print_json_value(const rapidjson::Value& value) { + rapidjson::StringBuffer buffer; + buffer.Clear(); + rapidjson::Writer writer(buffer); + value.Accept(writer); + return std::string(buffer.GetString()); +} + +void JsonFunctions::merge_objects(rapidjson::Value& dst_object, rapidjson::Value& src_object, + rapidjson::Document::AllocatorType& allocator) { + if (!src_object.IsObject()) { + return; + } + for (auto src_it = src_object.MemberBegin(); src_it != src_object.MemberEnd(); ++src_it) { + auto dst_it = dst_object.FindMember(src_it->name); + if (dst_it != dst_object.MemberEnd()) { + if (src_it->value.IsObject()) { + merge_objects(dst_it->value, src_it->value, allocator); + } else { + if (dst_it->value.IsNull()) { + dst_it->value = src_it->value; + } + } + } else { + dst_object.AddMember(src_it->name, src_it->value, allocator); + } + } +} + } // namespace doris diff --git a/be/src/exprs/json_functions.h b/be/src/exprs/json_functions.h index fcec257142fc7b..72aa522ff374fa 100644 --- a/be/src/exprs/json_functions.h +++ b/be/src/exprs/json_functions.h @@ -108,6 +108,13 @@ class JsonFunctions { static Status extract_from_object(simdjson::ondemand::object& obj, const std::vector& jsonpath, simdjson::ondemand::value* value) noexcept; + // src: {"a" : "b" {"c" : 1}, "e" : 123} + // dst: {"a" : "b" {"d" : 1}} + // merged: {"a" : "b" : {"c" : 1, "d" : 1}, "e" : 123} + static void merge_objects(rapidjson::Value& dst_object, rapidjson::Value& src_object, + rapidjson::Document::AllocatorType& allocator); + + static std::string print_json_value(const rapidjson::Value& value); private: static rapidjson::Value* match_value(const std::vector& parsed_paths, diff --git a/be/src/olap/base_tablet.cpp b/be/src/olap/base_tablet.cpp index d118c26c8bfdd8..d9d4a4c537ce17 100644 --- a/be/src/olap/base_tablet.cpp +++ b/be/src/olap/base_tablet.cpp @@ -21,6 +21,7 @@ #include "olap/tablet_schema_cache.h" #include "util/doris_metrics.h" +#include "vec/common/schema_util.h" namespace doris { using namespace ErrorCode; @@ -65,4 +66,14 @@ void BaseTablet::update_max_version_schema(const TabletSchemaSPtr& tablet_schema } } +void BaseTablet::update_by_least_common_schema(const TabletSchemaSPtr& update_schema) { + std::lock_guard wrlock(_meta_lock); + auto final_schema = std::make_shared(); + CHECK(_max_version_schema->schema_version() >= update_schema->schema_version()); + vectorized::schema_util::get_least_common_schema({_max_version_schema, update_schema}, + final_schema); + _max_version_schema = final_schema; + VLOG_DEBUG << "dump updated tablet schema: " << final_schema->dump_structure(); +} + } /* namespace doris */ diff --git a/be/src/olap/base_tablet.h b/be/src/olap/base_tablet.h index 975191628e04f0..b0ef40aeeb9946 100644 --- a/be/src/olap/base_tablet.h +++ b/be/src/olap/base_tablet.h @@ -65,6 +65,8 @@ class BaseTablet { void update_max_version_schema(const TabletSchemaSPtr& tablet_schema); + void update_by_least_common_schema(const TabletSchemaSPtr& update_schema); + TabletSchemaSPtr tablet_schema() const { std::shared_lock rlock(_meta_lock); return _max_version_schema; diff --git a/be/src/olap/compaction.cpp b/be/src/olap/compaction.cpp index d1fab950584b59..b025555166a391 100644 --- a/be/src/olap/compaction.cpp +++ b/be/src/olap/compaction.cpp @@ -249,8 +249,7 @@ void Compaction::build_basic_info() { std::vector rowset_metas(_input_rowsets.size()); std::transform(_input_rowsets.begin(), _input_rowsets.end(), rowset_metas.begin(), [](const RowsetSharedPtr& rowset) { return rowset->rowset_meta(); }); - _cur_tablet_schema = - _tablet->rowset_meta_with_max_schema_version(rowset_metas)->tablet_schema(); + _cur_tablet_schema = _tablet->tablet_schema_with_merged_max_schema_version(rowset_metas); } bool Compaction::handle_ordered_data_compaction() { diff --git a/be/src/olap/reader.cpp b/be/src/olap/reader.cpp index eab24a8ea81f92..41b44d44fdb0ca 100644 --- a/be/src/olap/reader.cpp +++ b/be/src/olap/reader.cpp @@ -646,7 +646,7 @@ Status TabletReader::init_reader_params_and_create_block( std::transform(input_rowsets.begin(), input_rowsets.end(), rowset_metas.begin(), [](const RowsetSharedPtr& rowset) { return rowset->rowset_meta(); }); TabletSchemaSPtr read_tablet_schema = - tablet->rowset_meta_with_max_schema_version(rowset_metas)->tablet_schema(); + tablet->tablet_schema_with_merged_max_schema_version(rowset_metas); TabletSchemaSPtr merge_tablet_schema = std::make_shared(); merge_tablet_schema->copy_from(*read_tablet_schema); diff --git a/be/src/olap/rowset/beta_rowset_writer.cpp b/be/src/olap/rowset/beta_rowset_writer.cpp index 080086a0a93b4c..e62ff6b33a4d7e 100644 --- a/be/src/olap/rowset/beta_rowset_writer.cpp +++ b/be/src/olap/rowset/beta_rowset_writer.cpp @@ -54,7 +54,7 @@ #include "util/time.h" #include "vec/columns/column.h" #include "vec/columns/column_object.h" -#include "vec/common/schema_util.h" // LocalSchemaChangeRecorder +#include "vec/common/schema_util.h" // variant column #include "vec/core/block.h" #include "vec/data_types/data_type_factory.hpp" @@ -123,8 +123,6 @@ Status BetaRowsetWriter::init(const RowsetWriterContext& rowset_writer_context) } _rowset_meta->set_tablet_uid(_context.tablet_uid); _rowset_meta->set_tablet_schema(_context.tablet_schema); - _context.schema_change_recorder = - std::make_shared(); _context.segment_collector = std::make_shared>(this); _context.file_writer_creator = std::make_shared>(this); RETURN_IF_ERROR(_segment_creator.init(_context)); @@ -446,6 +444,10 @@ Status BetaRowsetWriter::flush_memtable(vectorized::Block* block, int32_t segmen } TabletSchemaSPtr flush_schema; + if (_context.tablet_schema->num_variant_columns() > 0) { + // Unfold variant column + RETURN_IF_ERROR(expand_variant_to_subcolumns(*block, flush_schema)); + } { SCOPED_RAW_TIMER(&_segment_writer_ns); RETURN_IF_ERROR( @@ -522,6 +524,11 @@ Status BetaRowsetWriter::build(RowsetSharedPtr& rowset) { _rowset_meta->set_newest_write_timestamp(UnixSeconds()); } + // update rowset meta tablet schema if tablet schema updated + if (_context.tablet_schema->num_variant_columns() > 0) { + _rowset_meta->set_tablet_schema(_context.tablet_schema); + } + RETURN_NOT_OK_STATUS_WITH_WARN( RowsetFactory::create_rowset(_context.tablet_schema, _context.rowset_dir, _rowset_meta, &rowset), @@ -544,6 +551,24 @@ bool BetaRowsetWriter::_is_segment_overlapping( return false; } +// update tablet schema when meet variant columns, before commit_txn +// Eg. rowset schema: A(int), B(float), C(int), D(int) +// _tabelt->tablet_schema: A(bigint), B(double) +// => update_schema: A(bigint), B(double), C(int), D(int) +void BetaRowsetWriter::update_rowset_schema(TabletSchemaSPtr flush_schema) { + std::lock_guard lock(*(_context.schema_lock)); + TabletSchemaSPtr update_schema = std::make_shared(); + vectorized::schema_util::get_least_common_schema({_context.tablet_schema, flush_schema}, + update_schema); + CHECK_GE(update_schema->num_columns(), flush_schema->num_columns()) + << "Rowset merge schema columns count is " << update_schema->num_columns() + << ", but flush_schema is larger " << flush_schema->num_columns() + << " update_schema: " << update_schema->dump_structure() + << " flush_schema: " << flush_schema->dump_structure(); + _context.tablet_schema.swap(update_schema); + VLOG_DEBUG << "dump rs schema: " << _context.tablet_schema->dump_structure(); +} + void BetaRowsetWriter::_build_rowset_meta_with_spec_field( RowsetMetaSharedPtr rowset_meta, const RowsetMetaSharedPtr& spec_rowset_meta) { rowset_meta->set_num_rows(spec_rowset_meta->num_rows()); @@ -751,4 +776,113 @@ Status BetaRowsetWriter::flush_segment_writer_for_segcompaction( return Status::OK(); } +Status BetaRowsetWriter::expand_variant_to_subcolumns(vectorized::Block& block, + TabletSchemaSPtr& flush_schema) { + size_t num_rows = block.rows(); + if (num_rows == 0) { + return Status::OK(); + } + + std::vector variant_column_pos; + if (is_partial_update()) { + // check columns that used to do partial updates should not include variant + for (int i : get_partial_update_info()->update_cids) { + if (_context.tablet_schema->columns()[i].is_variant_type()) { + return Status::InvalidArgument("Not implement partial updates for variant"); + } + } + } else { + for (int i = 0; i < _context.tablet_schema->columns().size(); ++i) { + if (_context.tablet_schema->columns()[i].is_variant_type()) { + variant_column_pos.push_back(i); + } + } + } + + if (variant_column_pos.empty()) { + return Status::OK(); + } + + try { + // Parse each variant column from raw string column + vectorized::schema_util::parse_variant_columns(block, variant_column_pos); + vectorized::schema_util::finalize_variant_columns(block, variant_column_pos, + false /*not ingore sparse*/); + vectorized::schema_util::encode_variant_sparse_subcolumns(block, variant_column_pos); + } catch (const doris::Exception& e) { + // TODO more graceful, max_filter_ratio + LOG(WARNING) << "encounter execption " << e.to_string(); + return Status::InternalError(e.to_string()); + } + + // Dynamic Block consists of two parts, dynamic part of columns and static part of columns + // static extracted + // | --------- | ----------- | + // The static ones are original _tablet_schame columns + flush_schema = std::make_shared(); + flush_schema->copy_from(*_context.tablet_schema); + vectorized::Block flush_block(std::move(block)); + + // If column already exist in original tablet schema, then we pick common type + // and cast column to common type, and modify tablet column to common type, + // otherwise it's a new column, we should add to frontend + auto append_column = [&](const TabletColumn& parent_variant, auto& column_entry_from_object) { + const std::string& column_name = + parent_variant.name_lower_case() + "." + column_entry_from_object->path.get_path(); + const vectorized::DataTypePtr& final_data_type_from_object = + column_entry_from_object->data.get_least_common_type(); + TabletColumn tablet_column; + vectorized::PathInDataBuilder full_path_builder; + auto full_path = full_path_builder.append(parent_variant.name_lower_case(), false) + .append(column_entry_from_object->path.get_parts(), false) + .build(); + vectorized::schema_util::get_column_by_type( + final_data_type_from_object, column_name, tablet_column, + vectorized::schema_util::ExtraInfo {.unique_id = -1, + .parent_unique_id = parent_variant.unique_id(), + .path_info = full_path}); + flush_schema->append_column(std::move(tablet_column)); + flush_block.insert({column_entry_from_object->data.get_finalized_column_ptr()->get_ptr(), + final_data_type_from_object, column_name}); + }; + + // 1. Flatten variant column into flat columns, append flatten columns to the back of original Block and TabletSchema + // those columns are extracted columns, leave none extracted columns remain in original variant column, which is + // JSONB format at present. + // 2. Collect columns that need to be added or modified when data type changes or new columns encountered + for (size_t i = 0; i < variant_column_pos.size(); ++i) { + size_t variant_pos = variant_column_pos[i]; + vectorized::ColumnObject& object_column = assert_cast( + flush_block.get_by_position(variant_pos).column->assume_mutable_ref()); + const TabletColumn& parent_column = _context.tablet_schema->columns()[variant_pos]; + CHECK(object_column.is_finalized()); + std::shared_ptr root; + for (auto& entry : object_column.get_subcolumns()) { + if (entry->path.empty()) { + // root + root = entry; + continue; + } + append_column(parent_column, entry); + } + // Create new variant column and set root column + auto obj = vectorized::ColumnObject::create(true, false); + // '{}' indicates a root path + static_cast(obj.get())->add_sub_column( + {}, root->data.get_finalized_column_ptr()->assume_mutable(), + root->data.get_least_common_type()); + flush_block.get_by_position(variant_pos).column = obj->get_ptr(); + vectorized::PathInDataBuilder full_root_path_builder; + auto full_root_path = + full_root_path_builder.append(parent_column.name_lower_case(), false).build(); + flush_schema->mutable_columns()[variant_pos].set_path_info(full_root_path); + VLOG_DEBUG << "set root_path : " << full_root_path.get_path(); + } + update_rowset_schema(flush_schema); + block.swap(flush_block); + VLOG_DEBUG << "dump block: " << block.dump_data(); + VLOG_DEBUG << "dump flush schema: " << flush_schema->dump_structure(); + return Status::OK(); +} + } // namespace doris diff --git a/be/src/olap/rowset/beta_rowset_writer.h b/be/src/olap/rowset/beta_rowset_writer.h index 8918e30f3e2438..1821b670037d53 100644 --- a/be/src/olap/rowset/beta_rowset_writer.h +++ b/be/src/olap/rowset/beta_rowset_writer.h @@ -138,6 +138,8 @@ class BetaRowsetWriter : public RowsetWriter { return _context.partial_update_info && _context.partial_update_info->is_partial_update; } + const RowsetWriterContext& context() const override { return _context; } + private: Status _create_file_writer(std::string path, io::FileWriterPtr& file_writer); Status _check_segment_number_limit(); @@ -163,6 +165,14 @@ class BetaRowsetWriter : public RowsetWriter { Status _rename_compacted_segment_plain(uint64_t seg_id); Status _rename_compacted_indices(int64_t begin, int64_t end, uint64_t seg_id); + // Unfold variant column to Block + // Eg. [A | B | C | (D, E, F)] + // After unfold block structure changed to -> [A | B | C | D | E | F] + // The expanded D, E, F is dynamic part of the block + // The flushed Block columns should match exactly from the same type of frontend meta + Status expand_variant_to_subcolumns(vectorized::Block& block, TabletSchemaSPtr& flush_schema); + void update_rowset_schema(TabletSchemaSPtr flush_schema); + // build a tmp rowset for load segment to calc delete_bitmap // for this segment RowsetSharedPtr _build_tmp(); diff --git a/be/src/olap/rowset/beta_rowset_writer_v2.h b/be/src/olap/rowset/beta_rowset_writer_v2.h index 1a6db6df4092f7..d025383bee650a 100644 --- a/be/src/olap/rowset/beta_rowset_writer_v2.h +++ b/be/src/olap/rowset/beta_rowset_writer_v2.h @@ -104,6 +104,8 @@ class BetaRowsetWriterV2 : public RowsetWriter { PUniqueId load_id() override { return _context.load_id; } + const RowsetWriterContext& context() const override { return _context; } + Version version() override { return _context.version; } int64_t num_rows() const override { return _segment_creator.num_rows_written(); } diff --git a/be/src/olap/rowset/rowset_writer.h b/be/src/olap/rowset/rowset_writer.h index 8ba5666bf56f93..dc85283c4ec95b 100644 --- a/be/src/olap/rowset/rowset_writer.h +++ b/be/src/olap/rowset/rowset_writer.h @@ -156,6 +156,7 @@ class RowsetWriter { virtual std::shared_ptr get_partial_update_info() = 0; virtual bool is_partial_update() = 0; + virtual const RowsetWriterContext& context() const = 0; private: DISALLOW_COPY_AND_ASSIGN(RowsetWriter); diff --git a/be/src/olap/rowset/rowset_writer_context.h b/be/src/olap/rowset/rowset_writer_context.h index 6d4a6e7281779c..49a63b1e42ace3 100644 --- a/be/src/olap/rowset/rowset_writer_context.h +++ b/be/src/olap/rowset/rowset_writer_context.h @@ -48,7 +48,8 @@ struct RowsetWriterContext { version(Version(0, 0)), txn_id(0), tablet_uid(0, 0), - segments_overlap(OVERLAP_UNKNOWN) { + segments_overlap(OVERLAP_UNKNOWN), + schema_lock(new std::mutex) { load_id.set_hi(0); load_id.set_lo(0); } @@ -90,9 +91,6 @@ struct RowsetWriterContext { std::set skip_inverted_index; DataWriteType write_type = DataWriteType::TYPE_DEFAULT; BaseTabletSPtr tablet = nullptr; - // for tracing local schema change record - std::shared_ptr schema_change_recorder = - nullptr; std::shared_ptr mow_context; std::shared_ptr file_writer_creator; @@ -110,6 +108,9 @@ struct RowsetWriterContext { std::shared_ptr partial_update_info; bool is_transient_rowset_writer = false; + // In semi-structure senario tablet_schema will be updated concurrently, + // this lock need to be held when update.Use shared_ptr to avoid delete copy contructor + std::shared_ptr schema_lock; }; } // namespace doris diff --git a/be/src/olap/rowset/segment_v2/column_writer.cpp b/be/src/olap/rowset/segment_v2/column_writer.cpp index 9de11d83c10986..3891c1235e5218 100644 --- a/be/src/olap/rowset/segment_v2/column_writer.cpp +++ b/be/src/olap/rowset/segment_v2/column_writer.cpp @@ -353,6 +353,13 @@ Status ColumnWriter::create(const ColumnWriterOptions& opts, const TabletColumn* *writer = std::move(writer_local); return Status::OK(); } + case FieldType::OLAP_FIELD_TYPE_VARIANT: { + // Use ScalarColumnWriter to write it's only root data + std::unique_ptr writer_local = std::unique_ptr( + new ScalarColumnWriter(opts, std::move(field), file_writer)); + *writer = std::move(writer_local); + return Status::OK(); + } default: return Status::NotSupported("unsupported type for ColumnWriter: {}", std::to_string(int(field->type()))); diff --git a/be/src/olap/rowset/segment_v2/encoding_info.cpp b/be/src/olap/rowset/segment_v2/encoding_info.cpp index db41b15e3ded0f..ecf127e27a1d46 100644 --- a/be/src/olap/rowset/segment_v2/encoding_info.cpp +++ b/be/src/olap/rowset/segment_v2/encoding_info.cpp @@ -284,6 +284,10 @@ EncodingInfoResolver::EncodingInfoResolver() { _add_map(); _add_map(); + _add_map(); + _add_map(); + _add_map(); + _add_map(); _add_map(); _add_map(); diff --git a/be/src/olap/rowset/segment_v2/segment_writer.cpp b/be/src/olap/rowset/segment_v2/segment_writer.cpp index 9e2073b9fb4a98..6490b49f8b60cf 100644 --- a/be/src/olap/rowset/segment_v2/segment_writer.cpp +++ b/be/src/olap/rowset/segment_v2/segment_writer.cpp @@ -109,12 +109,16 @@ SegmentWriter::~SegmentWriter() { void SegmentWriter::init_column_meta(ColumnMetaPB* meta, uint32_t column_id, const TabletColumn& column, TabletSchemaSPtr tablet_schema) { meta->set_column_id(column_id); - meta->set_unique_id(column.unique_id()); meta->set_type(int(column.type())); meta->set_length(column.length()); meta->set_encoding(DEFAULT_ENCODING); meta->set_compression(_opts.compression_type); meta->set_is_nullable(column.is_nullable()); + meta->set_default_value(column.default_value()); + meta->set_precision(column.precision()); + meta->set_frac(column.frac()); + column.path_info().to_protobuf(meta->mutable_column_path_info(), column.parent_unique_id()); + meta->set_unique_id(column.unique_id()); for (uint32_t i = 0; i < column.get_subtype_count(); ++i) { init_column_meta(meta->add_children_columns(), column_id, column.get_sub_column(i), tablet_schema); @@ -181,57 +185,30 @@ Status SegmentWriter::init(const std::vector& col_ids, bool has_key) { break; } } - if (column.type() == FieldType::OLAP_FIELD_TYPE_STRUCT) { - opts.need_zone_map = false; - if (opts.need_bloom_filter) { - return Status::NotSupported("Do not support bloom filter for struct type"); - } - if (opts.need_bitmap_index) { - return Status::NotSupported("Do not support bitmap index for struct type"); - } - } - if (column.type() == FieldType::OLAP_FIELD_TYPE_ARRAY) { - opts.need_zone_map = false; - if (opts.need_bloom_filter) { - return Status::NotSupported("Do not support bloom filter for array type"); - } - if (opts.need_bitmap_index) { - return Status::NotSupported("Do not support bitmap index for array type"); - } - } - if (column.type() == FieldType::OLAP_FIELD_TYPE_JSONB) { - opts.need_zone_map = false; - if (opts.need_bloom_filter) { - return Status::NotSupported("Do not support bloom filter for jsonb type"); - } - if (opts.need_bitmap_index) { - return Status::NotSupported("Do not support bitmap index for jsonb type"); - } - } - if (column.type() == FieldType::OLAP_FIELD_TYPE_AGG_STATE) { - opts.need_zone_map = false; - if (opts.need_bloom_filter) { - return Status::NotSupported("Do not support bloom filter for agg_state type"); - } - if (opts.need_bitmap_index) { - return Status::NotSupported("Do not support bitmap index for agg_state type"); - } - } - if (column.type() == FieldType::OLAP_FIELD_TYPE_MAP) { - opts.need_zone_map = false; - if (opts.need_bloom_filter) { - return Status::NotSupported("Do not support bloom filter for map type"); - } - if (opts.need_bitmap_index) { - return Status::NotSupported("Do not support bitmap index for map type"); - } - } +#define CHECK_FIELD_TYPE(TYPE, type_name) \ + if (column.type() == FieldType::OLAP_FIELD_TYPE_##TYPE) { \ + opts.need_zone_map = false; \ + if (opts.need_bloom_filter) { \ + return Status::NotSupported("Do not support bloom filter for " type_name " type"); \ + } \ + if (opts.need_bitmap_index) { \ + return Status::NotSupported("Do not support bitmap index for " type_name " type"); \ + } \ + } + + CHECK_FIELD_TYPE(STRUCT, "struct") + CHECK_FIELD_TYPE(ARRAY, "array") + CHECK_FIELD_TYPE(JSONB, "jsonb") + CHECK_FIELD_TYPE(AGG_STATE, "agg_state") + CHECK_FIELD_TYPE(MAP, "map") + CHECK_FIELD_TYPE(VARIANT, "variant") + +#undef CHECK_FIELD_TYPE if (column.is_row_store_column()) { // smaller page size for row store column opts.data_page_size = config::row_column_page_size; } - std::unique_ptr writer; RETURN_IF_ERROR(ColumnWriter::create(opts, &column, _file_writer, &writer)); RETURN_IF_ERROR(writer->init()); diff --git a/be/src/olap/rowset/vertical_beta_rowset_writer.h b/be/src/olap/rowset/vertical_beta_rowset_writer.h index 8e318686db97b2..8251ad0a07ebe0 100644 --- a/be/src/olap/rowset/vertical_beta_rowset_writer.h +++ b/be/src/olap/rowset/vertical_beta_rowset_writer.h @@ -49,6 +49,8 @@ class VerticalBetaRowsetWriter : public BetaRowsetWriter { int64_t num_rows() const override { return _total_key_group_rows; } + virtual const RowsetWriterContext& context() const override { LOG(FATAL) << "Not implemented"; } + private: // only key group will create segment writer Status _create_segment_writer(const std::vector& column_ids, bool is_key, diff --git a/be/src/olap/rowset_builder.cpp b/be/src/olap/rowset_builder.cpp index afe7fd385ff235..894a782883be6b 100644 --- a/be/src/olap/rowset_builder.cpp +++ b/be/src/olap/rowset_builder.cpp @@ -53,6 +53,7 @@ #include "util/stopwatch.hpp" #include "util/time.h" #include "util/trace.h" +#include "vec/common/schema_util.h" #include "vec/core/block.h" namespace doris { @@ -301,6 +302,14 @@ Status RowsetBuilder::commit_txn() { auto storage_engine = StorageEngine::instance(); std::lock_guard l(_lock); SCOPED_TIMER(_commit_txn_timer); + if (_tablet->tablet_schema()->num_variant_columns() > 0) { + // update tablet schema when meet variant columns, before commit_txn + // Eg. rowset schema: A(int), B(float), C(int), D(int) + // _tabelt->tablet_schema: A(bigint), B(double) + // => update_schema: A(bigint), B(double), C(int), D(int) + const RowsetWriterContext& rw_ctx = _rowset_writer->context(); + _tablet->update_by_least_common_schema(rw_ctx.tablet_schema); + } Status res = storage_engine->txn_manager()->commit_txn(_req.partition_id, *tablet, _req.txn_id, _req.load_id, _rowset, false); diff --git a/be/src/olap/tablet.cpp b/be/src/olap/tablet.cpp index 4cc030130910a7..db1c2eb4ea2e6e 100644 --- a/be/src/olap/tablet.cpp +++ b/be/src/olap/tablet.cpp @@ -123,6 +123,7 @@ #include "util/work_thread_pool.hpp" #include "vec/columns/column.h" #include "vec/columns/column_string.h" +#include "vec/common/schema_util.h" #include "vec/common/string_ref.h" #include "vec/data_types/data_type.h" #include "vec/data_types/data_type_factory.hpp" @@ -277,7 +278,7 @@ Tablet::Tablet(TabletMetaSharedPtr tablet_meta, DataDir* data_dir, _max_version_schema = _tablet_meta->tablet_schema(); } else { _max_version_schema = - rowset_meta_with_max_schema_version(_tablet_meta->all_rs_metas())->tablet_schema(); + tablet_schema_with_merged_max_schema_version(_tablet_meta->all_rs_metas()); } DCHECK(_max_version_schema); } @@ -629,9 +630,9 @@ const RowsetSharedPtr Tablet::rowset_with_max_version() const { return iter->second; } -RowsetMetaSharedPtr Tablet::rowset_meta_with_max_schema_version( +TabletSchemaSPtr Tablet::tablet_schema_with_merged_max_schema_version( const std::vector& rowset_metas) { - return *std::max_element( + RowsetMetaSharedPtr max_schema_version_rs = *std::max_element( rowset_metas.begin(), rowset_metas.end(), [](const RowsetMetaSharedPtr& a, const RowsetMetaSharedPtr& b) { return !a->tablet_schema() @@ -641,6 +642,18 @@ RowsetMetaSharedPtr Tablet::rowset_meta_with_max_schema_version( : a->tablet_schema()->schema_version() < b->tablet_schema()->schema_version()); }); + TabletSchemaSPtr target_schema = max_schema_version_rs->tablet_schema(); + if (target_schema->num_variant_columns() > 0) { + // For variant columns tablet schema need to be the merged wide tablet schema + std::vector schemas; + std::transform(rowset_metas.begin(), rowset_metas.end(), std::back_inserter(schemas), + [](const RowsetMetaSharedPtr& rs_meta) { return rs_meta->tablet_schema(); }); + target_schema = std::make_shared(); + // TODO(lhy) maybe slow? + vectorized::schema_util::get_least_common_schema(schemas, target_schema); + VLOG_DEBUG << "dump schema: " << target_schema->dump_structure(); + } + return target_schema; } RowsetSharedPtr Tablet::_rowset_with_largest_size() { diff --git a/be/src/olap/tablet.h b/be/src/olap/tablet.h index d46a7f915cdb56..3c30b3805fa5af 100644 --- a/be/src/olap/tablet.h +++ b/be/src/olap/tablet.h @@ -161,7 +161,7 @@ class Tablet final : public BaseTablet { const RowsetSharedPtr rowset_with_max_version() const; - static RowsetMetaSharedPtr rowset_meta_with_max_schema_version( + static TabletSchemaSPtr tablet_schema_with_merged_max_schema_version( const std::vector& rowset_metas); Status add_inc_rowset(const RowsetSharedPtr& rowset); diff --git a/be/src/olap/tablet_meta.cpp b/be/src/olap/tablet_meta.cpp index b5f3b4fd36d748..76fed9d4aa3281 100644 --- a/be/src/olap/tablet_meta.cpp +++ b/be/src/olap/tablet_meta.cpp @@ -364,7 +364,8 @@ void TabletMeta::init_column_from_tcolumn(uint32_t unique_id, const TColumn& tco } for (size_t i = 0; i < tcolumn.children_column.size(); i++) { ColumnPB* children_column = column->add_children_columns(); - init_column_from_tcolumn(i, tcolumn.children_column[i], children_column); + init_column_from_tcolumn(tcolumn.children_column[i].col_unique_id, + tcolumn.children_column[i], children_column); } } diff --git a/be/src/udf/udf.cpp b/be/src/udf/udf.cpp index ecabc905ab8335..40f8e70ed0948d 100644 --- a/be/src/udf/udf.cpp +++ b/be/src/udf/udf.cpp @@ -57,6 +57,8 @@ std::unique_ptr FunctionContext::clone() { new_context->_constant_cols = _constant_cols; new_context->_fragment_local_fn_state = _fragment_local_fn_state; new_context->_check_overflow_for_decimal = _check_overflow_for_decimal; + new_context->_string_as_jsonb_string = _string_as_jsonb_string; + new_context->_jsonb_string_as_string = _jsonb_string_as_string; return new_context; } diff --git a/be/src/udf/udf.h b/be/src/udf/udf.h index a1413a5ab89047..e383904c5b4a25 100644 --- a/be/src/udf/udf.h +++ b/be/src/udf/udf.h @@ -80,6 +80,22 @@ class FunctionContext { return _check_overflow_for_decimal = check_overflow_for_decimal; } + void set_string_as_jsonb_string(bool string_as_jsonb_string) { + _string_as_jsonb_string = string_as_jsonb_string; + } + + void set_jsonb_string_as_string(bool jsonb_string_as_string) { + _jsonb_string_as_string = jsonb_string_as_string; + } + + // Cast flag, when enable string_as_jsonb_string, string casting to jsonb will not parse string + // instead just insert a string literal + bool string_as_jsonb_string() const { return _string_as_jsonb_string; } + + // Cast flag, when enable jsonb_string_as_string, jsonb string casting to string will not parse string + // instead just insert a string literal + bool jsonb_string_as_string() const { return _jsonb_string_as_string; } + // Sets an error for this UDF. If this is called, this will trigger the // query to fail. // Note: when you set error for the UDFs used in Data Load, you should @@ -162,6 +178,9 @@ class FunctionContext { bool _check_overflow_for_decimal = false; + bool _string_as_jsonb_string = false; + bool _jsonb_string_as_string = false; + std::string _string_result; vectorized::Arena arena; diff --git a/be/src/util/jsonb_document.h b/be/src/util/jsonb_document.h index 657438fefee0d0..fb3dd360e3021d 100644 --- a/be/src/util/jsonb_document.h +++ b/be/src/util/jsonb_document.h @@ -197,27 +197,33 @@ class JsonbDocument { public: bool operator==(const JsonbDocument& other) const { - LOG(FATAL) << "comparing between JsonbDocument is not supported"; + assert(false); + return false; } bool operator!=(const JsonbDocument& other) const { - LOG(FATAL) << "comparing between JsonbDocument is not supported"; + assert(false); + return false; } bool operator<=(const JsonbDocument& other) const { - LOG(FATAL) << "comparing between JsonbDocument is not supported"; + assert(false); + return false; } bool operator>=(const JsonbDocument& other) const { - LOG(FATAL) << "comparing between JsonbDocument is not supported"; + assert(false); + return false; } bool operator<(const JsonbDocument& other) const { - LOG(FATAL) << "comparing between JsonbDocument is not supported"; + assert(false); + return false; } bool operator>(const JsonbDocument& other) const { - LOG(FATAL) << "comparing between JsonbDocument is not supported"; + assert(false); + return false; } private: diff --git a/be/src/vec/aggregate_functions/aggregate_function_approx_count_distinct.cpp b/be/src/vec/aggregate_functions/aggregate_function_approx_count_distinct.cpp index 8add4627f200a4..d0dcafd0144ed2 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_approx_count_distinct.cpp +++ b/be/src/vec/aggregate_functions/aggregate_function_approx_count_distinct.cpp @@ -22,6 +22,7 @@ #include "vec/columns/column_array.h" #include "vec/columns/column_decimal.h" #include "vec/columns/column_map.h" +#include "vec/columns/column_object.h" #include "vec/columns/column_string.h" #include "vec/columns/column_struct.h" #include "vec/data_types/data_type.h" diff --git a/be/src/vec/aggregate_functions/aggregate_function_reader_first_last.h b/be/src/vec/aggregate_functions/aggregate_function_reader_first_last.h index b10d69b2d4b382..110e1bcc1b0442 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_reader_first_last.h +++ b/be/src/vec/aggregate_functions/aggregate_function_reader_first_last.h @@ -23,6 +23,7 @@ #include "vec/columns/column_array.h" #include "vec/columns/column_map.h" #include "vec/columns/column_nullable.h" +#include "vec/columns/column_object.h" #include "vec/columns/column_struct.h" #include "vec/columns/column_vector.h" #include "vec/data_types/data_type_decimal.h" diff --git a/be/src/vec/columns/column.h b/be/src/vec/columns/column.h index cfb9163820fbe5..5202c51a3daa6c 100644 --- a/be/src/vec/columns/column.h +++ b/be/src/vec/columns/column.h @@ -144,6 +144,9 @@ class IColumn : public COW { return nullptr; } + /// Some columns may require finalization before using of other operations. + virtual void finalize() {} + // Only used on ColumnDictionary virtual void set_rowset_segment_id(std::pair rowset_segment_id) {} @@ -590,6 +593,8 @@ class IColumn : public COW { virtual bool is_hll() const { return false; } + virtual bool is_variant() const { return false; } + virtual bool is_quantile_state() const { return false; } // true if column has null element @@ -641,6 +646,18 @@ class IColumn : public COW { return 0; } + /// Returns ratio of values in column, that are equal to default value of column. + /// Checks only @sample_ratio ratio of rows. + virtual double get_ratio_of_default_rows(double sample_ratio = 1.0) const { + LOG(FATAL) << fmt::format("get_ratio_of_default_rows of column {} are not implemented.", + get_name()); + return 0.0; + } + + /// Template is to devirtualize calls to 'isDefaultAt' method. + template + double get_ratio_of_default_rows_impl(double sample_ratio) const; + /// Column is ColumnVector of numbers or ColumnConst of it. Note that Nullable columns are not numeric. /// Implies is_fixed_and_contiguous. virtual bool is_numeric() const { return false; } @@ -649,8 +666,6 @@ class IColumn : public COW { virtual bool is_column_decimal() const { return false; } - virtual bool is_predicate_column() const { return false; } - virtual bool is_column_dictionary() const { return false; } virtual bool is_column_array() const { return false; } @@ -662,9 +677,6 @@ class IColumn : public COW { /// If the only value column can contain is NULL. virtual bool only_null() const { return false; } - /// Can be inside ColumnNullable. - virtual bool can_be_inside_nullable() const { return false; } - virtual bool low_cardinality() const { return false; } virtual void sort_column(const ColumnSorter* sorter, EqualFlags& flags, diff --git a/be/src/vec/columns/column_array.cpp b/be/src/vec/columns/column_array.cpp index ca3b6c12da5bb9..374dd17a88a6a7 100644 --- a/be/src/vec/columns/column_array.cpp +++ b/be/src/vec/columns/column_array.cpp @@ -481,6 +481,10 @@ void ColumnArray::insert_range_from(const IColumn& src, size_t start, size_t len } } +double ColumnArray::get_ratio_of_default_rows(double sample_ratio) const { + return get_ratio_of_default_rows_impl(sample_ratio); +} + ColumnPtr ColumnArray::filter(const Filter& filt, ssize_t result_size_hint) const { if (typeid_cast(data.get())) return filter_number(filt, result_size_hint); diff --git a/be/src/vec/columns/column_array.h b/be/src/vec/columns/column_array.h index c37fb48ba52b20..8c39573ba0f7fe 100644 --- a/be/src/vec/columns/column_array.h +++ b/be/src/vec/columns/column_array.h @@ -127,7 +127,6 @@ class ColumnArray final : public COWHelper { std::string get_name() const override; const char* get_family_name() const override { return "Array"; } bool is_column_array() const override { return true; } - bool can_be_inside_nullable() const override { return true; } MutableColumnPtr clone_resized(size_t size) const override; size_t size() const override; void resize(size_t n) override; @@ -266,6 +265,8 @@ class ColumnArray final : public COWHelper { ColumnPtr index(const IColumn& indexes, size_t limit) const override; + double get_ratio_of_default_rows(double sample_ratio) const override; + private: // [[2,1,5,9,1], [1,2,4]] --> data column [2,1,5,9,1,1,2,4], offset[-1] = 0, offset[0] = 5, offset[1] = 8 // [[[2,1,5],[9,1]], [[1,2]]] --> data column [3 column array], offset[-1] = 0, offset[0] = 2, offset[1] = 3 diff --git a/be/src/vec/columns/column_complex.h b/be/src/vec/columns/column_complex.h index b25ae9f1577291..6c752d082b4044 100644 --- a/be/src/vec/columns/column_complex.h +++ b/be/src/vec/columns/column_complex.h @@ -233,8 +233,6 @@ class ColumnComplexType final : public COWHelper> "compare_at for " + std::string(get_family_name())); } - bool can_be_inside_nullable() const override { return true; } - bool is_fixed_and_contiguous() const override { return true; } size_t size_of_value_if_fixed() const override { return sizeof(T); } diff --git a/be/src/vec/columns/column_decimal.h b/be/src/vec/columns/column_decimal.h index 6c1e8893a3d94a..30c4f1116fd1f0 100644 --- a/be/src/vec/columns/column_decimal.h +++ b/be/src/vec/columns/column_decimal.h @@ -106,7 +106,6 @@ class ColumnDecimal final : public COWHelper> { const char* get_family_name() const override { return "ColumnDictionary"; } - [[noreturn]] MutableColumnPtr clone_resized(size_t size) const override { - LOG(FATAL) << "clone_resized not supported in ColumnDictionary"; + MutableColumnPtr clone_resized(size_t size) const override { + DCHECK(size == 0); + return this->create(); } void insert(const Field& x) override { @@ -145,8 +146,6 @@ class ColumnDictionary final : public COWHelper> { LOG(FATAL) << "compare_at not supported in ColumnDictionary"; } - bool can_be_inside_nullable() const override { return true; } - bool is_fixed_and_contiguous() const override { return true; } void get_indices_of_non_default_rows(IColumn::Offsets64& indices, size_t from, diff --git a/be/src/vec/columns/column_dummy.h b/be/src/vec/columns/column_dummy.h new file mode 100644 index 00000000000000..a152dc9751a0e1 --- /dev/null +++ b/be/src/vec/columns/column_dummy.h @@ -0,0 +1,175 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// This file is copied from +// https://github.com/ClickHouse/ClickHouse/blob/master/src/AggregateFunctions/IColumnDummy.h +// and modified by Doris + +#pragma once + +#include "vec/columns/column.h" +#include "vec/columns/columns_common.h" +#include "vec/common/arena.h" +#include "vec/common/pod_array.h" + +namespace doris::vectorized { + +/** Base class for columns-constants that contain a value that is not in the `Field`. + * Not a full-fledged column and is used in a special way. + */ +class IColumnDummy : public IColumn { +public: + IColumnDummy() : s(0) {} + IColumnDummy(size_t s_) : s(s_) {} + +public: + virtual MutableColumnPtr clone_dummy(size_t s_) const = 0; + + MutableColumnPtr clone_resized(size_t s) const override { return clone_dummy(s); } + size_t size() const override { return s; } + void insert_default() override { ++s; } + void pop_back(size_t n) override { s -= n; } + size_t byte_size() const override { return 0; } + size_t allocated_bytes() const override { return 0; } + int compare_at(size_t, size_t, const IColumn&, int) const override { return 0; } + + [[noreturn]] Field operator[](size_t) const override { + LOG(FATAL) << "Cannot get value from " << get_name(); + } + + void get(size_t, Field&) const override { + LOG(FATAL) << "Cannot get value from " << get_name(); + } + + void insert(const Field&) override { + LOG(FATAL) << "Cannot insert element into " << get_name(); + } + + StringRef get_data_at(size_t) const override { return {}; } + + void insert_data(const char*, size_t) override { ++s; } + + StringRef serialize_value_into_arena(size_t /*n*/, Arena& arena, + char const*& begin) const override { + return {arena.alloc_continue(0, begin), 0}; + } + + const char* deserialize_and_insert_from_arena(const char* pos) override { + ++s; + return pos; + } + + void insert_from(const IColumn&, size_t) override { ++s; } + + void insert_range_from(const IColumn& /*src*/, size_t /*start*/, size_t length) override { + s += length; + } + + void insert_indices_from(const IColumn& src, const int* indices_begin, + const int* indices_end) override { + s += (indices_end - indices_begin); + } + + ColumnPtr filter(const Filter& filt, ssize_t /*result_size_hint*/) const override { + return clone_dummy(count_bytes_in_filter(filt)); + } + + size_t filter(const Filter& filter) override { + const auto result_size = count_bytes_in_filter(filter); + s = result_size; + return result_size; + } + + ColumnPtr permute(const Permutation& perm, size_t limit) const override { + if (s != perm.size()) { + LOG(FATAL) << "Size of permutation doesn't match size of column."; + } + + return clone_dummy(limit ? std::min(s, limit) : s); + } + + void get_permutation(bool /*reverse*/, size_t /*limit*/, int /*nan_direction_hint*/, + Permutation& res) const override { + res.resize(s); + for (size_t i = 0; i < s; ++i) res[i] = i; + } + + ColumnPtr replicate(const Offsets& offsets) const override { + column_match_offsets_size(s, offsets.size()); + + return clone_dummy(offsets.back()); + } + + void replicate(const uint32_t* indexs, size_t target_size, IColumn& column) const override { + LOG(FATAL) << "Not implemented"; + } + + MutableColumns scatter(ColumnIndex num_columns, const Selector& selector) const override { + if (s != selector.size()) { + LOG(FATAL) << "Size of selector doesn't match size of column."; + } + + std::vector counts(num_columns); + for (auto idx : selector) ++counts[idx]; + + MutableColumns res(num_columns); + for (size_t i = 0; i < num_columns; ++i) res[i] = clone_resized(counts[i]); + + return res; + } + + void append_data_by_selector(MutableColumnPtr& res, + const IColumn::Selector& selector) const override { + size_t num_rows = size(); + + if (num_rows < selector.size()) { + LOG(FATAL) << fmt::format("Size of selector: {}, is larger than size of column:{}", + selector.size(), num_rows); + } + + res->reserve(num_rows); + + for (size_t i = 0; i < selector.size(); ++i) res->insert_from(*this, selector[i]); + } + + void addSize(size_t delta) { s += delta; } + + bool is_dummy() const override { return true; } + + void replace_column_data(const IColumn& rhs, size_t row, size_t self_row = 0) override { + LOG(FATAL) << "should not call the method in column dummy"; + } + + void replace_column_data_default(size_t self_row = 0) override { + LOG(FATAL) << "should not call the method in column dummy"; + } + + void get_indices_of_non_default_rows(Offsets64&, size_t, size_t) const override { + LOG(FATAL) << "should not call the method in column dummy"; + } + + ColumnPtr index(const IColumn& indexes, size_t limit) const override { + if (indexes.size() < limit) { + LOG(FATAL) << "Size of indexes is less than required."; + } + return clone_dummy(limit ? limit : s); + } + +protected: + size_t s; +}; + +} // namespace doris::vectorized diff --git a/be/src/vec/columns/column_fixed_length_object.h b/be/src/vec/columns/column_fixed_length_object.h index dce6666f132f91..5b9733748d09fd 100644 --- a/be/src/vec/columns/column_fixed_length_object.h +++ b/be/src/vec/columns/column_fixed_length_object.h @@ -50,8 +50,6 @@ class ColumnFixedLengthObject final : public COWHelper +double IColumn::get_ratio_of_default_rows_impl(double sample_ratio) const { + if (sample_ratio <= 0.0 || sample_ratio > 1.0) { + LOG(FATAL) << "Value of 'sample_ratio' must be in interval (0.0; 1.0], but got: " + << sample_ratio; + } + static constexpr auto max_number_of_rows_for_full_search = 1000; + size_t num_rows = size(); + size_t num_sampled_rows = std::min(static_cast(num_rows * sample_ratio), num_rows); + size_t num_checked_rows = 0; + size_t res = 0; + if (num_sampled_rows == num_rows || num_rows <= max_number_of_rows_for_full_search) { + for (size_t i = 0; i < num_rows; ++i) + res += static_cast(*this).is_default_at(i); + num_checked_rows = num_rows; + } else if (num_sampled_rows != 0) { + for (size_t i = 0; i < num_rows; ++i) { + if (num_checked_rows * num_rows <= i * num_sampled_rows) { + res += static_cast(*this).is_default_at(i); + ++num_checked_rows; + } + } + } + if (num_checked_rows == 0) { + return 0.0; + } + return static_cast(res) / num_checked_rows; +} + } // namespace doris::vectorized diff --git a/be/src/vec/columns/column_map.h b/be/src/vec/columns/column_map.h index 551b6f9bfd6328..8ec97f6c7d61e7 100644 --- a/be/src/vec/columns/column_map.h +++ b/be/src/vec/columns/column_map.h @@ -94,8 +94,6 @@ class ColumnMap final : public COWHelper { MutableColumnPtr clone_resized(size_t size) const override; - bool can_be_inside_nullable() const override { return true; } - Field operator[](size_t n) const override; void get(size_t n, Field& res) const override; StringRef get_data_at(size_t n) const override; diff --git a/be/src/vec/columns/column_nothing.h b/be/src/vec/columns/column_nothing.h new file mode 100644 index 00000000000000..8a10eec8b6f36d --- /dev/null +++ b/be/src/vec/columns/column_nothing.h @@ -0,0 +1,44 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// This file is copied from +// https://github.com/ClickHouse/ClickHouse/blob/master/src/AggregateFunctions/ColumnNothing.h +// and modified by Doris + +#pragma once + +#include "vec/columns/column_dummy.h" + +namespace doris::vectorized { + +class ColumnNothing final : public COWHelper { +private: + friend class COWHelper; + + ColumnNothing(size_t s_) { s = s_; } + + ColumnNothing(const ColumnNothing&) = default; + +public: + const char* get_family_name() const override { return "Nothing"; } + MutableColumnPtr clone_dummy(size_t s_) const override { return ColumnNothing::create(s_); } + + bool structure_equals(const IColumn& rhs) const override { + return typeid(rhs) == typeid(ColumnNothing); + } +}; + +} // namespace doris::vectorized diff --git a/be/src/vec/columns/column_nullable.cpp b/be/src/vec/columns/column_nullable.cpp index 42b88ac7ae9af4..4f25a3f4b159a3 100644 --- a/be/src/vec/columns/column_nullable.cpp +++ b/be/src/vec/columns/column_nullable.cpp @@ -44,10 +44,6 @@ ColumnNullable::ColumnNullable(MutableColumnPtr&& nested_column_, MutableColumnP nested_column = assert_cast(*nested_column).get_nested_column_ptr(); } - if (!get_nested_column().can_be_inside_nullable()) { - LOG(FATAL) << get_nested_column().get_name() << " cannot be inside Nullable column"; - } - if (is_column_const(*null_map)) { LOG(FATAL) << "ColumnNullable cannot have constant null map"; } @@ -564,9 +560,7 @@ bool ColumnNullable::has_null(size_t size) const { } ColumnPtr make_nullable(const ColumnPtr& column, bool is_nullable) { - if (is_column_nullable(*column)) { - return column; - } + if (is_column_nullable(*column)) return column; if (is_column_const(*column)) { return ColumnConst::create( diff --git a/be/src/vec/columns/column_nullable.h b/be/src/vec/columns/column_nullable.h index 3b97e708d1155b..6d2c52b23a654a 100644 --- a/be/src/vec/columns/column_nullable.h +++ b/be/src/vec/columns/column_nullable.h @@ -93,6 +93,7 @@ class ColumnNullable final : public COWHelper { bool is_null_at(size_t n) const override { return assert_cast(*null_map).get_data()[n] != 0; } + bool is_default_at(size_t n) const override { return is_null_at(n); } Field operator[](size_t n) const override; void get(size_t n, Field& res) const override; bool get_bool(size_t n) const override { @@ -354,6 +355,10 @@ class ColumnNullable final : public COWHelper { return get_ptr(); } + double get_ratio_of_default_rows(double sample_ratio) const override { + return get_ratio_of_default_rows_impl(sample_ratio); + } + void convert_dict_codes_if_necessary() override { get_nested_column().convert_dict_codes_if_necessary(); } diff --git a/be/src/vec/columns/column_object.cpp b/be/src/vec/columns/column_object.cpp index f3571c8ba29674..a59b52ee0bc19d 100644 --- a/be/src/vec/columns/column_object.cpp +++ b/be/src/vec/columns/column_object.cpp @@ -23,29 +23,41 @@ #include #include #include +#include +#include #include #include #include +#include #include #include "common/exception.h" #include "common/status.h" +#include "olap/olap_common.h" +#include "util/defer_op.h" +#include "util/simd/bits.h" #include "vec/columns/column_array.h" #include "vec/columns/column_nullable.h" +#include "vec/columns/column_string.h" #include "vec/columns/columns_number.h" #include "vec/common/field_visitors.h" #include "vec/common/schema_util.h" +#include "vec/common/string_buffer.hpp" +#include "vec/core/column_with_type_and_name.h" #include "vec/core/field.h" +#include "vec/core/types.h" #include "vec/data_types/convert_field_to_type.h" #include "vec/data_types/data_type_array.h" #include "vec/data_types/data_type_factory.hpp" +#include "vec/data_types/data_type_jsonb.h" #include "vec/data_types/data_type_nothing.h" #include "vec/data_types/get_least_supertype.h" // IWYU pragma: no_include #include "common/compiler_util.h" // IWYU pragma: keep #include "common/logging.h" +#include "exprs/json_functions.h" #include "vec/aggregate_functions/aggregate_function.h" #include "vec/columns/column.h" #include "vec/columns/column_vector.h" @@ -58,90 +70,57 @@ namespace doris::vectorized { namespace { -DataTypePtr create_array_of_type(DataTypePtr type, size_t num_dimensions) { +DataTypePtr create_array_of_type(DataTypePtr type, size_t num_dimensions, bool is_nullable) { + const DataTypeNullable* nullable = typeid_cast(type.get()); + if ((nullable && + typeid_cast(nullable->get_nested_type().get())) || + typeid_cast(type.get())) { + // JSONB type MUST NOT wrapped in ARRAY column, it should be top level. + // So we ignored num_dimensions. + return type; + } for (size_t i = 0; i < num_dimensions; ++i) { type = std::make_shared(std::move(type)); + if (is_nullable) { + // wrap array with nullable + type = make_nullable(type); + } } return type; } -DataTypePtr getBaseTypeOfArray(const DataTypePtr& type) { +DataTypePtr get_base_type_of_array(const DataTypePtr& type) { /// Get raw pointers to avoid extra copying of type pointers. const DataTypeArray* last_array = nullptr; const auto* current_type = type.get(); + if (const auto* nullable = typeid_cast(current_type)) { + current_type = nullable->get_nested_type().get(); + } while (const auto* type_array = typeid_cast(current_type)) { current_type = type_array->get_nested_type().get(); last_array = type_array; + if (const auto* nullable = typeid_cast(current_type)) { + current_type = nullable->get_nested_type().get(); + } } return last_array ? last_array->get_nested_type() : type; } -size_t getNumberOfDimensions(const IDataType& type) { - if (const auto* type_array = typeid_cast(&type)) { - return type_array->get_number_of_dimensions(); - } - return 0; -} - -DataTypePtr get_data_type_by_column(const IColumn& column) { - // Removed in the future PR - // assert(false); - return nullptr; -} - -/// Recreates column with default scalar values and keeps sizes of arrays. -ColumnPtr recreate_column_with_default_value(const ColumnPtr& column, - const DataTypePtr& scalar_type, - size_t num_dimensions) { - const auto* column_array = check_and_get_column(column.get()); - if (column_array && num_dimensions) { - return ColumnArray::create( - recreate_column_with_default_value(column_array->get_data_ptr(), scalar_type, - num_dimensions - 1), - IColumn::mutate(column_array->get_offsets_ptr())); +size_t get_number_of_dimensions(const IDataType& type) { + int num_dimensions = 0; + const auto* current_type = &type; + if (const auto* nullable = typeid_cast(current_type)) { + current_type = nullable->get_nested_type().get(); } - return create_array_of_type(scalar_type, num_dimensions) - ->create_column() - ->clone_resized(column->size()); -} - -Array create_empty_array_field(size_t num_dimensions) { - assert(num_dimensions != 0); - Array array; - Array* current_array = &array; - for (size_t i = 1; i < num_dimensions; ++i) { - current_array->push_back(Array()); - current_array = ¤t_array->back().get(); - } - return array; -} - -/// Replaces NULL fields to given field or empty array. -class FieldVisitorReplaceNull : public StaticVisitor { -public: - explicit FieldVisitorReplaceNull(const Field& replacement_, size_t num_dimensions_) - : replacement(replacement_), num_dimensions(num_dimensions_) {} - Field operator()(const Null&) const { - return num_dimensions ? create_empty_array_field(num_dimensions) : replacement; - } - Field operator()(const Array& x) const { - assert(num_dimensions > 0); - const size_t size = x.size(); - Array res(size); - for (size_t i = 0; i < size; ++i) { - res[i] = apply_visitor(FieldVisitorReplaceNull(replacement, num_dimensions - 1), x[i]); + while (const auto* type_array = typeid_cast(current_type)) { + current_type = type_array->get_nested_type().get(); + num_dimensions += 1; + if (const auto* nullable = typeid_cast(current_type)) { + current_type = nullable->get_nested_type().get(); } - return res; } - template - Field operator()(const T& x) const { - return x; - } - -private: - const Field& replacement; - size_t num_dimensions; -}; + return num_dimensions; +} /// Calculates number of dimensions in array field. /// Returns 0 for scalar fields. @@ -149,23 +128,12 @@ class FieldVisitorToNumberOfDimensions : public StaticVisitor { public: size_t operator()(const Array& x) const { const size_t size = x.size(); - std::optional dimensions; + size_t dimensions = 0; for (size_t i = 0; i < size; ++i) { - /// Do not count Nulls, because they will be replaced by default - /// values with proper number of dimensions. - if (x[i].is_null()) { - continue; - } - size_t current_dimensions = apply_visitor(*this, x[i]); - if (!dimensions) { - dimensions = current_dimensions; - } else if (current_dimensions != *dimensions) { - throw doris::Exception(doris::ErrorCode::INVALID_ARGUMENT, - "Number of dimensions mismatched among array elements"); - return 0; - } + size_t element_dimensions = apply_visitor(*this, x[i]); + dimensions = std::max(dimensions, element_dimensions); } - return 1 + dimensions.value_or(0); + return 1 + dimensions; } template size_t operator()(const T&) const { @@ -202,18 +170,25 @@ class FieldVisitorToScalarType : public StaticVisitor { return 0; } size_t operator()(const Int64& x) { - // // Only Int64 | Int32 at present - // field_types.insert(FieldType::Int64); - // type_indexes.insert(TypeIndex::Int64); - // return 0; field_types.insert(FieldType::Int64); - if (x <= std::numeric_limits::max() && x >= std::numeric_limits::min()) { + if (x <= std::numeric_limits::max() && x >= std::numeric_limits::min()) { + type_indexes.insert(TypeIndex::Int8); + } else if (x <= std::numeric_limits::max() && + x >= std::numeric_limits::min()) { + type_indexes.insert(TypeIndex::Int16); + } else if (x <= std::numeric_limits::max() && + x >= std::numeric_limits::min()) { type_indexes.insert(TypeIndex::Int32); } else { type_indexes.insert(TypeIndex::Int64); } return 0; } + size_t operator()(const JsonbField& x) { + field_types.insert(FieldType::JSONB); + type_indexes.insert(TypeIndex::JSONB); + return 0; + } size_t operator()(const Null&) { have_nulls = true; return 0; @@ -226,7 +201,7 @@ class FieldVisitorToScalarType : public StaticVisitor { return 0; } void get_scalar_type(DataTypePtr* type) const { - get_least_supertype(type_indexes, type, true /*compatible with string type*/); + get_least_supertype(type_indexes, type); } bool contain_nulls() const { return have_nulls; } bool need_convert_field() const { return field_types.size() > 1; } @@ -252,15 +227,18 @@ void get_field_info(const Field& field, FieldInfo* info) { }; } -ColumnObject::Subcolumn::Subcolumn(MutableColumnPtr&& data_, bool is_nullable_) - : least_common_type(get_data_type_by_column(*data_)), is_nullable(is_nullable_) { +ColumnObject::Subcolumn::Subcolumn(MutableColumnPtr&& data_, DataTypePtr type, bool is_nullable_, + bool is_root_) + : least_common_type(type), is_nullable(is_nullable_), is_root(is_root_) { data.push_back(std::move(data_)); + data_types.push_back(type); } -ColumnObject::Subcolumn::Subcolumn(size_t size_, bool is_nullable_) +ColumnObject::Subcolumn::Subcolumn(size_t size_, bool is_nullable_, bool is_root_) : least_common_type(std::make_shared()), is_nullable(is_nullable_), - num_of_defaults_in_prefix(size_) {} + num_of_defaults_in_prefix(size_), + is_root(is_root_) {} size_t ColumnObject::Subcolumn::Subcolumn::size() const { size_t res = num_of_defaults_in_prefix; @@ -294,7 +272,8 @@ void ColumnObject::Subcolumn::insert(Field field) { void ColumnObject::Subcolumn::add_new_column_part(DataTypePtr type) { data.push_back(type->create_column()); - least_common_type = LeastCommonType {std::move(type)}; + least_common_type = LeastCommonType {type}; + data_types.push_back(type); } void ColumnObject::Subcolumn::insert(Field field, FieldInfo info) { @@ -305,45 +284,42 @@ void ColumnObject::Subcolumn::insert(Field field, FieldInfo info) { } auto column_dim = least_common_type.get_dimensions(); auto value_dim = info.num_dimensions; - if (is_nothing(least_common_type.getBase())) { + if (is_nothing(least_common_type.get_base())) { column_dim = value_dim; } if (is_nothing(base_type)) { value_dim = column_dim; } - if (value_dim != column_dim) { - throw doris::Exception(doris::ErrorCode::INVALID_ARGUMENT, - "Dimension of types mismatched between inserted value and column, " - "expected:{}, but meet:{} for type:{}", - column_dim, value_dim, least_common_type.get()->get_name()); + bool type_changed = false; + if (value_dim != column_dim || info.num_dimensions >= 2) { + // Deduce to JSONB + VLOG_DEBUG << fmt::format( + "Dimension of types mismatched between inserted value and column, " + "expected:{}, but meet:{} for type:{}", + column_dim, value_dim, least_common_type.get()->get_name()); + base_type = std::make_shared(); + value_dim = 0; + type_changed = true; } if (is_nullable && !is_nothing(base_type)) { base_type = make_nullable(base_type); } - // alawys nullable at present - if (!is_nullable && info.have_nulls) { - field = apply_visitor(FieldVisitorReplaceNull(base_type->get_default(), value_dim), - std::move(field)); - } - // need replace muli dimensions array which contains null. eg. [[1, 2, 3], null] -> [[1, 2, 3], []] - // since column array doesnt known null's dimension - if (info.num_dimensions >= 2 && info.have_nulls) { - field = apply_visitor(FieldVisitorReplaceNull(base_type->get_default(), value_dim), - std::move(field)); - } - bool type_changed = false; - const auto& least_common_base_type = least_common_type.getBase(); + const auto& least_common_base_type = least_common_type.get_base(); if (data.empty()) { - add_new_column_part(create_array_of_type(std::move(base_type), value_dim)); + add_new_column_part(create_array_of_type(std::move(base_type), value_dim, is_nullable)); } else if (!least_common_base_type->equals(*base_type) && !is_nothing(base_type)) { if (!schema_util::is_conversion_required_between_integers(*base_type, *least_common_base_type)) { - get_least_supertype(DataTypes {std::move(base_type), least_common_base_type}, - &base_type, true /*compatible with string type*/); + get_least_supertype( + DataTypes {std::move(base_type), least_common_base_type}, &base_type); type_changed = true; + if (is_nullable) { + base_type = make_nullable(base_type); + } if (!least_common_base_type->equals(*base_type)) { - add_new_column_part(create_array_of_type(std::move(base_type), value_dim)); + add_new_column_part( + create_array_of_type(std::move(base_type), value_dim, is_nullable)); } } } @@ -358,53 +334,121 @@ void ColumnObject::Subcolumn::insert(Field field, FieldInfo info) { } void ColumnObject::Subcolumn::insertRangeFrom(const Subcolumn& src, size_t start, size_t length) { - assert(src.is_finalized()); - const auto& src_column = src.data.back(); - const auto& src_type = src.least_common_type.get(); + assert(start + length <= src.size()); + size_t end = start + length; + // num_rows += length; if (data.empty()) { - add_new_column_part(src.least_common_type.get()); - data.back()->insert_range_from(*src_column, start, length); - } else if (least_common_type.get()->equals(*src_type)) { - data.back()->insert_range_from(*src_column, start, length); - } else { - DataTypePtr new_least_common_type = nullptr; - get_least_supertype(DataTypes {least_common_type.get(), src_type}, &new_least_common_type, - true /*compatible with string type*/); - ColumnPtr casted_column; - Status st = schema_util::cast_column({src_column, src_type, ""}, new_least_common_type, - &casted_column); + add_new_column_part(src.get_least_common_type()); + } else if (!least_common_type.get()->equals(*src.get_least_common_type())) { + DataTypePtr new_least_common_type; + get_least_supertype( + DataTypes {least_common_type.get(), src.get_least_common_type()}, + &new_least_common_type); + if (!new_least_common_type->equals(*least_common_type.get())) { + add_new_column_part(std::move(new_least_common_type)); + } + } + if (end <= src.num_of_defaults_in_prefix) { + data.back()->insert_many_defaults(length); + return; + } + if (start < src.num_of_defaults_in_prefix) { + data.back()->insert_many_defaults(src.num_of_defaults_in_prefix - start); + } + auto insert_from_part = [&](const auto& column, const auto& column_type, size_t from, + size_t n) { + assert(from + n <= column->size()); + if (column_type->equals(*least_common_type.get())) { + data.back()->insert_range_from(*column, from, n); + return; + } + /// If we need to insert large range, there is no sense to cut part of column and cast it. + /// Casting of all column and inserting from it can be faster. + /// Threshold is just a guess. + if (n * 3 >= column->size()) { + ColumnPtr casted_column; + Status st = schema_util::cast_column({column, column_type, ""}, least_common_type.get(), + &casted_column); + if (!st.ok()) { + throw doris::Exception(ErrorCode::INVALID_ARGUMENT, + st.to_string() + ", real_code:{}", st.code()); + } + data.back()->insert_range_from(*casted_column, from, n); + return; + } + auto casted_column = column->cut(from, n); + Status st = schema_util::cast_column({casted_column, column_type, ""}, + least_common_type.get(), &casted_column); if (!st.ok()) { throw doris::Exception(ErrorCode::INVALID_ARGUMENT, st.to_string() + ", real_code:{}", st.code()); } - if (!least_common_type.get()->equals(*new_least_common_type)) { - add_new_column_part(std::move(new_least_common_type)); - } - data.back()->insert_range_from(*casted_column, start, length); + data.back()->insert_range_from(*casted_column, 0, n); + }; + size_t pos = 0; + size_t processed_rows = src.num_of_defaults_in_prefix; + /// Find the first part of the column that intersects the range. + while (pos < src.data.size() && processed_rows + src.data[pos]->size() < start) { + processed_rows += src.data[pos]->size(); + ++pos; + } + /// Insert from the first part of column. + if (pos < src.data.size() && processed_rows < start) { + size_t part_start = start - processed_rows; + size_t part_length = std::min(src.data[pos]->size() - part_start, end - start); + insert_from_part(src.data[pos], src.data_types[pos], part_start, part_length); + processed_rows += src.data[pos]->size(); + ++pos; + } + /// Insert from the parts of column in the middle of range. + while (pos < src.data.size() && processed_rows + src.data[pos]->size() < end) { + insert_from_part(src.data[pos], src.data_types[pos], 0, src.data[pos]->size()); + processed_rows += src.data[pos]->size(); + ++pos; + } + /// Insert from the last part of column if needed. + if (pos < src.data.size() && processed_rows < end) { + size_t part_end = end - processed_rows; + insert_from_part(src.data[pos], src.data_types[pos], 0, part_end); } } bool ColumnObject::Subcolumn::is_finalized() const { - return data.empty() || (data.size() == 1 && num_of_defaults_in_prefix == 0); + return num_of_defaults_in_prefix == 0 && (data.empty() || (data.size() == 1)); } template -ColumnPtr ColumnObject::apply_for_subcolumns(Func&& func, std::string_view func_name) const { +MutableColumnPtr ColumnObject::apply_for_subcolumns(Func&& func) const { if (!is_finalized()) { - // LOG(FATAL) << "Cannot " << func_name << " non-finalized ColumnObject"; - throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR, - "Cannot {} non-finalized ColumnObject", func_name); + auto finalized = clone_finalized(); + auto& finalized_object = assert_cast(*finalized); + return finalized_object.apply_for_subcolumns(std::forward(func)); } - auto res = ColumnObject::create(is_nullable); + auto res = ColumnObject::create(is_nullable, false); for (const auto& subcolumn : subcolumns) { auto new_subcolumn = func(subcolumn->data.get_finalized_column()); - res->add_sub_column(subcolumn->path, new_subcolumn->assume_mutable()); + res->add_sub_column(subcolumn->path, new_subcolumn->assume_mutable(), + subcolumn->data.get_least_common_type()); } return res; } ColumnPtr ColumnObject::index(const IColumn& indexes, size_t limit) const { return apply_for_subcolumns( - [&](const auto& subcolumn) { return subcolumn.index(indexes, limit); }, "index"); + [&](const auto& subcolumn) { return subcolumn.index(indexes, limit); }); +} + +bool ColumnObject::Subcolumn::check_if_sparse_column(size_t num_rows) { + constexpr static size_t s_threshold_rows_estimate_sparse_column = 1000; + if (num_rows < s_threshold_rows_estimate_sparse_column) { + return false; + } + std::vector defaults_ratio; + for (size_t i = 0; i < data.size(); ++i) { + defaults_ratio.push_back(data[i]->get_ratio_of_default_rows()); + } + double default_ratio = std::accumulate(defaults_ratio.begin(), defaults_ratio.end(), 0.0) / + defaults_ratio.size(); + return default_ratio >= config::ratio_of_defaults_as_sparse_column; } void ColumnObject::Subcolumn::finalize() { @@ -415,37 +459,35 @@ void ColumnObject::Subcolumn::finalize() { data[0] = data[0]->convert_to_full_column_if_const(); return; } - const auto& to_type = least_common_type.get(); + DataTypePtr to_type = least_common_type.get(); + if (is_root) { + // Root always JSONB type + to_type = is_nullable ? make_nullable(std::make_shared()) + : std::make_shared(); + least_common_type = LeastCommonType {to_type}; + } auto result_column = to_type->create_column(); if (num_of_defaults_in_prefix) { result_column->insert_many_defaults(num_of_defaults_in_prefix); } - for (auto& part : data) { + for (size_t i = 0; i < data.size(); ++i) { + auto& part = data[i]; + auto from_type = data_types[i]; part = part->convert_to_full_column_if_const(); - auto from_type = get_data_type_by_column(*part); size_t part_size = part->size(); if (!from_type->equals(*to_type)) { - auto offsets = ColumnUInt64::create(); - auto& offsets_data = offsets->get_data(); - /// We need to convert only non-default values and then recreate column - /// with default value of new type, because default values (which represents misses in data) - /// may be inconsistent between types (e.g "0" in UInt64 and empty string in String). - part->get_indices_of_non_default_rows(offsets_data, 0, part_size); - if (offsets->size() == part_size) { - ColumnPtr ptr; - static_cast(schema_util::cast_column({part, from_type, ""}, to_type, &ptr)); - part = ptr; - } else { - auto values = part->index(*offsets, offsets->size()); - static_cast( - schema_util::cast_column({values, from_type, ""}, to_type, &values)); - part = values->create_with_offsets(offsets_data, to_type->get_default(), part_size, - /*shift=*/0); + ColumnPtr ptr; + Status st = schema_util::cast_column({part, from_type, ""}, to_type, &ptr); + if (!st.ok()) { + throw doris::Exception(ErrorCode::INVALID_ARGUMENT, + st.to_string() + ", real_code:{}", st.code()); } + part = ptr; } result_column->insert_range_from(*part, 0, part_size); } data = {std::move(result_column)}; + data_types = {std::move(to_type)}; num_of_defaults_in_prefix = 0; } @@ -481,7 +523,9 @@ void ColumnObject::Subcolumn::pop_back(size_t n) { n -= column->size(); } } - data.resize(data.size() - num_removed); + size_t sz = data.size() - num_removed; + data.resize(sz); + data_types.resize(sz); num_of_defaults_in_prefix -= n; } @@ -494,25 +538,6 @@ Field ColumnObject::Subcolumn::get_last_field() const { return (*last_part)[last_part->size() - 1]; } -ColumnObject::Subcolumn ColumnObject::Subcolumn::recreate_with_default_values( - const FieldInfo& field_info) const { - auto scalar_type = field_info.scalar_type; - if (is_nullable) { - scalar_type = make_nullable(scalar_type); - } - Subcolumn new_subcolumn; - new_subcolumn.least_common_type = - LeastCommonType {create_array_of_type(scalar_type, field_info.num_dimensions)}; - new_subcolumn.is_nullable = is_nullable; - new_subcolumn.num_of_defaults_in_prefix = num_of_defaults_in_prefix; - new_subcolumn.data.reserve(data.size()); - for (const auto& part : data) { - new_subcolumn.data.push_back( - recreate_column_with_default_value(part, scalar_type, field_info.num_dimensions)); - } - return new_subcolumn; -} - IColumn& ColumnObject::Subcolumn::get_finalized_column() { assert(is_finalized()); return *data[0]; @@ -528,6 +553,11 @@ const ColumnPtr& ColumnObject::Subcolumn::get_finalized_column_ptr() const { return data[0]; } +ColumnPtr& ColumnObject::Subcolumn::get_finalized_column_ptr() { + assert(is_finalized()); + return data[0]; +} + void ColumnObject::Subcolumn::remove_nullable() { assert(is_finalized()); data[0] = doris::vectorized::remove_nullable(data[0]); @@ -536,10 +566,19 @@ void ColumnObject::Subcolumn::remove_nullable() { ColumnObject::Subcolumn::LeastCommonType::LeastCommonType(DataTypePtr type_) : type(std::move(type_)), - base_type(getBaseTypeOfArray(type)), - num_dimensions(getNumberOfDimensions(*type)) {} + base_type(get_base_type_of_array(type)), + num_dimensions(get_number_of_dimensions(*type)) { + if (!WhichDataType(type).is_nothing()) { + least_common_type_serder = type->get_serde(); + } +} -ColumnObject::ColumnObject(bool is_nullable_) : is_nullable(is_nullable_), num_rows(0) {} +ColumnObject::ColumnObject(bool is_nullable_, bool create_root_) + : is_nullable(is_nullable_), num_rows(0) { + if (create_root_) { + subcolumns.create_root(Subcolumn(0, is_nullable, true /*root*/)); + } +} ColumnObject::ColumnObject(Subcolumns&& subcolumns_, bool is_nullable_) : is_nullable(is_nullable_), @@ -571,12 +610,11 @@ size_t ColumnObject::size() const { } MutableColumnPtr ColumnObject::clone_resized(size_t new_size) const { - /// cloneResized with new_size == 0 is used for cloneEmpty(). - if (new_size != 0) { - throw doris::Exception(doris::ErrorCode::INTERNAL_ERROR, - "ColumnObject doesn't support resize to non-zero length"); + if (new_size == 0) { + return ColumnObject::create(is_nullable); } - return ColumnObject::create(is_nullable); + return apply_for_subcolumns( + [&](const auto& subcolumn) { return subcolumn.clone_resized(new_size); }); } size_t ColumnObject::byte_size() const { @@ -596,24 +634,43 @@ size_t ColumnObject::allocated_bytes() const { } void ColumnObject::for_each_subcolumn(ColumnCallback callback) { - if (!is_finalized()) { - assert(false); - } for (auto& entry : subcolumns) { - callback(entry->data.data.back()); + for (auto& part : entry->data.data) { + callback(part); + } } } -void ColumnObject::try_insert_from(const IColumn& src, size_t n) { +void ColumnObject::insert_from(const IColumn& src, size_t n) { + const auto& src_v = assert_cast(src); + // optimize when src and this column are scalar variant, since try_insert is inefficiency + if (src_v.is_scalar_variant() && is_scalar_variant() && + src_v.get_root_type()->equals(*get_root_type()) && src_v.is_finalized() && is_finalized()) { + assert_cast(*get_root()).insert_from(*src_v.get_root(), n); + ++num_rows; + return; + } return try_insert(src[n]); } void ColumnObject::try_insert(const Field& field) { + if (field.get_type() != Field::Types::VariantMap) { + auto* root = get_subcolumn({}); + if (!root) { + doris::Exception(doris::ErrorCode::INVALID_ARGUMENT, "Failed to find root column_path"); + } + root->insert(field); + ++num_rows; + return; + } const auto& object = field.get(); phmap::flat_hash_set inserted; size_t old_size = size(); for (const auto& [key_str, value] : object) { - PathInData key(key_str); + PathInData key; + if (!key_str.empty()) { + key = PathInData(key_str); + } inserted.insert(key_str); if (!has_subcolumn(key)) { bool succ = add_sub_column(key, old_size); @@ -646,10 +703,17 @@ void ColumnObject::insert_default() { Field ColumnObject::operator[](size_t n) const { if (!is_finalized()) { - assert(false); + const_cast(this)->finalize(); } VariantMap map; for (const auto& entry : subcolumns) { + if (WhichDataType(remove_nullable(entry->data.data_types.back())).is_json()) { + // JsonbFiled is special case + Field f = JsonbField(); + (*entry->data.data.back()).get(n, f); + map[entry->path.get_path()] = std::move(f); + continue; + } map[entry->path.get_path()] = (*entry->data.data.back())[n]; } return map; @@ -657,11 +721,15 @@ Field ColumnObject::operator[](size_t n) const { void ColumnObject::get(size_t n, Field& res) const { if (!is_finalized()) { - assert(false); + const_cast(this)->finalize(); } auto& map = res.get(); for (const auto& entry : subcolumns) { auto it = map.try_emplace(entry->path.get_path()).first; + if (WhichDataType(remove_nullable(entry->data.data_types.back())).is_json()) { + // JsonbFiled is special case + it->second = JsonbField(); + } entry->data.data.back()->get(n, it->second); } } @@ -672,59 +740,52 @@ Status ColumnObject::try_insert_indices_from(const IColumn& src, const int* indi if (*x == -1) { ColumnObject::insert_default(); } else { - ColumnObject::try_insert_from(src, *x); + ColumnObject::insert_from(src, *x); } } finalize(); return Status::OK(); } -void ColumnObject::try_insert_range_from(const IColumn& src, size_t start, size_t length) { +FieldInfo ColumnObject::Subcolumn::get_subcolumn_field_info() const { + const auto& base_type = least_common_type.get_base(); + return FieldInfo { + .scalar_type = base_type, + .have_nulls = base_type->is_nullable(), + .need_convert = false, + .num_dimensions = least_common_type.get_dimensions(), + }; +} + +void ColumnObject::insert_range_from(const IColumn& src, size_t start, size_t length) { const auto& src_object = assert_cast(src); - if (UNLIKELY(src_object.empty())) { - return; + for (const auto& entry : src_object.subcolumns) { + if (!has_subcolumn(entry->path)) { + add_sub_column(entry->path, num_rows); + } + auto* subcolumn = get_subcolumn(entry->path); + subcolumn->insertRangeFrom(entry->data, start, length); } for (auto& entry : subcolumns) { - if (src_object.has_subcolumn(entry->path)) { - auto* subcolumn = src_object.get_subcolumn(entry->path); - if (!subcolumn) { - throw doris::Exception(doris::ErrorCode::INVALID_ARGUMENT, - "Failed to find sub column {}", entry->path.get_path()); - } - entry->data.insertRangeFrom(*subcolumn, start, length); - } else { + if (!src_object.has_subcolumn(entry->path)) { entry->data.insertManyDefaults(length); } } - for (const auto& entry : src_object.subcolumns) { - if (!has_subcolumn(entry->path)) { - bool succ = false; - if (entry->path.has_nested_part()) { - const auto& base_type = entry->data.get_least_common_typeBase(); - FieldInfo field_info { - .scalar_type = base_type, - .have_nulls = base_type->is_nullable(), - .need_convert = false, - .num_dimensions = entry->data.get_dimensions(), - }; - succ = add_nested_subcolumn(entry->path, field_info, num_rows); - } else { - succ = add_sub_column(entry->path, num_rows); - } - if (!succ) { - throw doris::Exception(doris::ErrorCode::INVALID_ARGUMENT, - "Failed to add column {}", entry->path.get_path()); - } - auto* subcolumn = get_subcolumn(entry->path); - if (!subcolumn) { - throw doris::Exception(doris::ErrorCode::INVALID_ARGUMENT, - "Failed to find sub column {}", entry->path.get_path()); - } - subcolumn->insertRangeFrom(entry->data, start, length); - } - } num_rows += length; finalize(); +#ifndef NDEBUG + check_consistency(); +#endif +} + +ColumnPtr ColumnObject::replicate(const Offsets& offsets) const { + return apply_for_subcolumns( + [&](const auto& subcolumn) { return subcolumn.replicate(offsets); }); +} + +ColumnPtr ColumnObject::permute(const Permutation& perm, size_t limit) const { + return apply_for_subcolumns( + [&](const auto& subcolumn) { return subcolumn.permute(perm, limit); }); } void ColumnObject::pop_back(size_t length) { @@ -756,9 +817,27 @@ bool ColumnObject::has_subcolumn(const PathInData& key) const { return subcolumns.find_leaf(key) != nullptr; } -bool ColumnObject::add_sub_column(const PathInData& key, MutableColumnPtr&& subcolumn) { +bool ColumnObject::add_sub_column(const PathInData& key, MutableColumnPtr&& subcolumn, + DataTypePtr type) { size_t new_size = subcolumn->size(); - bool inserted = subcolumns.add(key, Subcolumn(std::move(subcolumn), is_nullable)); + doc_structure = nullptr; + if (key.empty() && subcolumns.empty()) { + // create root + subcolumns.create_root(Subcolumn(std::move(subcolumn), type, is_nullable, true)); + num_rows = new_size; + return true; + } + if (key.empty() && ((!subcolumns.get_root()->is_scalar()) || + is_nothing(subcolumns.get_root()->data.get_least_common_type()))) { + // update root + subcolumns.get_mutable_root()->modify_to_scalar( + Subcolumn(std::move(subcolumn), type, is_nullable, true)); + if (num_rows == 0) { + num_rows = new_size; + } + return true; + } + bool inserted = subcolumns.add(key, Subcolumn(std::move(subcolumn), type, is_nullable)); if (!inserted) { VLOG_DEBUG << "Duplicated sub column " << key.get_path(); return false; @@ -773,6 +852,21 @@ bool ColumnObject::add_sub_column(const PathInData& key, MutableColumnPtr&& subc } bool ColumnObject::add_sub_column(const PathInData& key, size_t new_size) { + if (key.empty() && subcolumns.empty()) { + // create root + subcolumns.create_root(Subcolumn(new_size, is_nullable, true)); + num_rows = new_size; + return true; + } + if (key.empty() && (!subcolumns.get_root()->is_scalar())) { + // update none scalar root column to scalar node + subcolumns.get_mutable_root()->modify_to_scalar(Subcolumn(new_size, is_nullable, true)); + if (num_rows == 0) { + num_rows = new_size; + } + return true; + } + doc_structure = nullptr; bool inserted = subcolumns.add(key, Subcolumn(new_size, is_nullable)); if (!inserted) { VLOG_DEBUG << "Duplicated sub column " << key.get_path(); @@ -787,40 +881,6 @@ bool ColumnObject::add_sub_column(const PathInData& key, size_t new_size) { return true; } -bool ColumnObject::add_nested_subcolumn(const PathInData& key, const FieldInfo& field_info, - size_t new_size) { - assert(key.has_nested_part()); - bool inserted = false; - /// We find node that represents the same Nested type as @key. - const auto* nested_node = subcolumns.find_best_match(key); - if (nested_node) { - /// Find any leaf of Nested subcolumn. - const auto* leaf = doris::vectorized::ColumnObject::Subcolumns::find_leaf( - nested_node, [&](const auto&) { return true; }); - assert(leaf); - /// Recreate subcolumn with default values and the same sizes of arrays. - auto new_subcolumn = leaf->data.recreate_with_default_values(field_info); - /// It's possible that we have already inserted value from current row - /// to this subcolumn. So, adjust size to expected. - if (new_subcolumn.size() > new_size) { - new_subcolumn.pop_back(new_subcolumn.size() - new_size); - } - assert(new_subcolumn.size() == new_size); - inserted = subcolumns.add(key, new_subcolumn); - } else { - /// If node was not found just add subcolumn with empty arrays. - inserted = subcolumns.add(key, Subcolumn(new_size, is_nullable)); - } - if (!inserted) { - VLOG_DEBUG << "Subcolumn already exists"; - return false; - } - if (num_rows == 0) { - num_rows = new_size; - } - return true; -} - PathsInData ColumnObject::getKeys() const { PathsInData keys; keys.reserve(subcolumns.size()); @@ -845,28 +905,318 @@ bool ColumnObject::is_finalized() const { [](const auto& entry) { return entry->data.is_finalized(); }); } -void ColumnObject::finalize() { +static bool check_if_valid_column_name(const PathInData& path) { + static const std::regex COLUMN_NAME_REGEX("^[_a-zA-Z@0-9][.a-zA-Z0-9_+-/>is_column_array() && !result_column->is_nullable()) { + auto new_null_map = ColumnUInt8::create(); + new_null_map->reserve(result_column->size()); + auto& null_map_data = new_null_map->get_data(); + auto array = static_cast(result_column.get()); + for (size_t i = 0; i < array->size(); ++i) { + null_map_data.push_back(array->is_default_at(i)); + } + result_column = ColumnNullable::create(std::move(result_column), std::move(new_null_map)); + data_types[0] = make_nullable(data_types[0]); + least_common_type = LeastCommonType {data_types[0]}; + } +} + +rapidjson::Value* find_leaf_node_by_path(rapidjson::Value& json, const PathInData& path, + int idx = 0) { + if (idx >= path.get_parts().size()) { + return &json; + } + + std::string_view current_key = path.get_parts()[idx].key; + if (!json.IsObject()) { + return nullptr; + } + rapidjson::Value name(current_key.data(), current_key.size()); + auto it = json.FindMember(name); + if (it == json.MemberEnd()) { + return nullptr; + } + rapidjson::Value& current = it->value; + // if (idx == path.get_parts().size() - 1) { + // return ¤t; + // } + return find_leaf_node_by_path(current, path, idx + 1); +} + +void find_and_set_leave_value(const IColumn* column, const PathInData& path, + const DataTypeSerDeSPtr& type, rapidjson::Value& root, + rapidjson::Document::AllocatorType& allocator, int row) { + const auto* nullable = assert_cast(column); + if (nullable->is_null_at(row)) { + return; + } + // TODO could cache the result of leaf nodes with it's path info + rapidjson::Value* target = find_leaf_node_by_path(root, path); + if (UNLIKELY(!target)) { + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + root.Accept(writer); + LOG(FATAL) << "could not find path " << path.get_path() + << ", root: " << std::string(buffer.GetString(), buffer.GetSize()); + } + type->write_one_cell_to_json(*column, *target, allocator, row); +} + +// compact null values +// {"a" : {"b" : "d" {"n" : null}, "e" : null}, "c" : 10 } +// after compact -> {"a" : {"c"} : 10} +void compact_null_values(rapidjson::Value& json, rapidjson::Document::AllocatorType& allocator) { + if (!json.IsObject() || json.IsNull()) { + return; + } + + rapidjson::Value::MemberIterator it = json.MemberBegin(); + while (it != json.MemberEnd()) { + rapidjson::Value& value = it->value; + if (value.IsNull()) { + it = json.EraseMember(it); + continue; + } + compact_null_values(value, allocator); + if (value.IsObject() && value.ObjectEmpty()) { + it = json.EraseMember(it); + continue; + } + ++it; + } +} + +// Construct rapidjson value from Subcolumns +void get_json_by_column_tree(rapidjson::Value& root, rapidjson::Document::AllocatorType& allocator, + const ColumnObject::Subcolumns::Node* node_root) { + if (node_root == nullptr || node_root->children.empty()) { + root.SetNull(); + return; + } + root.SetObject(); + for (auto it = node_root->children.begin(); it != node_root->children.end(); ++it) { + auto child = it->get_second(); + rapidjson::Value value(rapidjson::kObjectType); + get_json_by_column_tree(value, allocator, child.get()); + root.AddMember(rapidjson::StringRef(it->get_first().data, it->get_first().size), value, + allocator); + } +} + +bool ColumnObject::serialize_one_row_to_string(int row, std::string* output) const { + if (!is_finalized()) { + const_cast(this)->finalize(); + } + rapidjson::StringBuffer buf; + if (is_scalar_variant()) { + auto type = get_root_type(); + *output = type->to_string(*get_root(), row); + return true; + } + bool res = serialize_one_row_to_json_format(row, &buf, nullptr); + if (res) { + // TODO avoid copy + *output = std::string(buf.GetString(), buf.GetSize()); + } + return res; +} + +bool ColumnObject::serialize_one_row_to_string(int row, BufferWritable& output) const { + if (!is_finalized()) { + const_cast(this)->finalize(); + } + if (is_scalar_variant()) { + auto type = get_root_type(); + type->to_string(*get_root(), row, output); + return true; + } + rapidjson::StringBuffer buf; + bool res = serialize_one_row_to_json_format(row, &buf, nullptr); + if (res) { + output.write(buf.GetString(), buf.GetLength()); + } + return res; +} + +bool ColumnObject::serialize_one_row_to_json_format(int row, rapidjson::StringBuffer* output, + bool* is_null) const { + CHECK(is_finalized()); + if (subcolumns.empty()) { + if (is_null != nullptr) { + *is_null = true; + } else { + rapidjson::Value root(rapidjson::kNullType); + rapidjson::Writer writer(*output); + return root.Accept(writer); + } + return true; + } + CHECK(size() > row); + rapidjson::StringBuffer buffer; + rapidjson::Value root(rapidjson::kNullType); + if (doc_structure == nullptr) { + doc_structure = std::make_shared(); + rapidjson::Document::AllocatorType& allocator = doc_structure->GetAllocator(); + get_json_by_column_tree(*doc_structure, allocator, subcolumns.get_root()); + } + if (!doc_structure->IsNull()) { + root.CopyFrom(*doc_structure, doc_structure->GetAllocator()); + } +#ifndef NDEBUG + VLOG_DEBUG << "dump structure " << JsonFunctions::print_json_value(*doc_structure); +#endif + for (const auto& subcolumn : subcolumns) { + find_and_set_leave_value(subcolumn->data.get_finalized_column_ptr(), subcolumn->path, + subcolumn->data.get_least_common_type_serde(), root, + doc_structure->GetAllocator(), row); + } + compact_null_values(root, doc_structure->GetAllocator()); + if (root.IsNull() && is_null != nullptr) { + // Fast path + *is_null = true; + } else { + output->Clear(); + rapidjson::Writer writer(*output); + return root.Accept(writer); + } + return true; +} + +void ColumnObject::merge_sparse_to_root_column() { + CHECK(is_finalized()); + if (sparse_columns.empty()) { + return; + } + ColumnPtr src = subcolumns.get_mutable_root()->data.get_finalized_column_ptr(); + MutableColumnPtr mresult = src->clone_empty(); + const ColumnNullable* src_null = assert_cast(src.get()); + const ColumnString* src_column_ptr = + assert_cast(&src_null->get_nested_column()); + rapidjson::StringBuffer buffer; + doc_structure = std::make_shared(); + rapidjson::Document::AllocatorType& allocator = doc_structure->GetAllocator(); + get_json_by_column_tree(*doc_structure, allocator, sparse_columns.get_root()); + +#ifndef NDEBUG + VLOG_DEBUG << "dump structure " << JsonFunctions::print_json_value(*doc_structure); +#endif + + ColumnNullable* result_column_nullable = + assert_cast(mresult->assume_mutable().get()); + ColumnString* result_column_ptr = + assert_cast(&result_column_nullable->get_nested_column()); + result_column_nullable->reserve(num_rows); + // parse each row to jsonb + for (size_t i = 0; i < num_rows; ++i) { + // root is not null, store original value, eg. the root is scalar type like '[1]' + if (!src_null->empty() && !src_null->is_null_at(i)) { + result_column_ptr->insert_data(src_column_ptr->get_data_at(i).data, + src_column_ptr->get_data_at(i).size); + result_column_nullable->get_null_map_data().push_back(0); + continue; + } + + // parse and encode sparse columns + buffer.Clear(); + rapidjson::Value root(rapidjson::kNullType); + if (!doc_structure->IsNull()) { + root.CopyFrom(*doc_structure, doc_structure->GetAllocator()); + } + size_t null_count = 0; + for (const auto& subcolumn : sparse_columns) { + auto& column = subcolumn->data.get_finalized_column_ptr(); + if (assert_cast(*column).is_null_at(i)) { + ++null_count; + continue; + } + find_and_set_leave_value(column, subcolumn->path, + subcolumn->data.get_least_common_type_serde(), root, + doc_structure->GetAllocator(), i); + } + + // all null values, store null to sparse root + if (null_count == sparse_columns.size()) { + result_column_ptr->insert_default(); + result_column_nullable->get_null_map_data().push_back(1); + continue; + } + + // encode sparse columns into jsonb format + compact_null_values(root, doc_structure->GetAllocator()); + // parse as jsonb value and put back to rootnode + // TODO, we could convert to jsonb directly from rapidjson::Value for better performance, instead of parsing + JsonbParser parser; + rapidjson::Writer writer(buffer); + root.Accept(writer); + bool res = parser.parse(buffer.GetString(), buffer.GetSize()); + CHECK(res) << "buffer:" << std::string(buffer.GetString(), buffer.GetSize()) + << ", row_num:" << i; + result_column_ptr->insert_data(parser.getWriter().getOutput()->getBuffer(), + parser.getWriter().getOutput()->getSize()); + result_column_nullable->get_null_map_data().push_back(0); + } + + // assign merged column + subcolumns.get_mutable_root()->data.get_finalized_column_ptr() = mresult->get_ptr(); +} + +void ColumnObject::finalize(bool ignore_sparse) { Subcolumns new_subcolumns; + // finalize root first + if (!ignore_sparse || !is_null_root()) { + new_subcolumns.create_root(subcolumns.get_root()->data); + new_subcolumns.get_mutable_root()->data.finalize(); + } for (auto&& entry : subcolumns) { const auto& least_common_type = entry->data.get_least_common_type(); - /// Do not add subcolumns, which consists only from NULLs. - if (is_nothing(getBaseTypeOfArray(least_common_type))) { + /// Do not add subcolumns, which consists only from NULLs + if (is_nothing(get_base_type_of_array(least_common_type))) { continue; } - if (!entry->data.data.empty()) { - entry->data.finalize(); - new_subcolumns.add(entry->path, entry->data); + entry->data.finalize(); + entry->data.wrapp_array_nullable(); + + if (entry->data.is_root) { + continue; + } + + // Check and spilit sparse subcolumns + if (!ignore_sparse && (entry->data.check_if_sparse_column(num_rows) || + !check_if_valid_column_name(entry->path))) { + // TODO seperate ambiguous path + sparse_columns.add(entry->path, entry->data); + continue; } + + new_subcolumns.add(entry->path, entry->data); } - /// If all subcolumns were skipped add a dummy subcolumn, - /// because Tuple type must have at least one element. - // if (new_subcolumns.empty()) { - // new_subcolumns.add( - // PathInData {COLUMN_NAME_DUMMY}, - // Subcolumn {static_cast(ColumnUInt8::create(old_size, 0)), - // is_nullable}); - // } std::swap(subcolumns, new_subcolumns); + doc_structure = nullptr; +} + +void ColumnObject::finalize() { + finalize(true); +} + +void ColumnObject::ensure_root_node_type(const DataTypePtr& expected_root_type) { + auto& root = subcolumns.get_mutable_root()->data; + if (!root.get_least_common_type()->equals(*expected_root_type)) { + // make sure the root type is alawys as expected + ColumnPtr casted_column; + static_cast( + schema_util::cast_column(ColumnWithTypeAndName {root.get_finalized_column_ptr(), + root.get_least_common_type(), ""}, + expected_root_type, &casted_column)); + root.data[0] = casted_column; + root.data_types[0] = expected_root_type; + root.least_common_type = Subcolumn::LeastCommonType {expected_root_type}; + } } bool ColumnObject::empty() const { @@ -888,33 +1238,77 @@ void ColumnObject::strip_outer_array() { new_subcolumns.add(entry->path, Subcolumn {base_column->assume_mutable(), is_nullable}); num_rows = base_column->size(); } - /// If all subcolumns were skipped add a dummy subcolumn, - /// because Tuple type must have at least one element. - // if (new_subcolumns.empty()) { - // new_subcolumns.add( - // PathInData {COLUMN_NAME_DUMMY}, - // Subcolumn {static_cast(ColumnUInt8::create(old_size, 0)), - // is_nullable}); - // } std::swap(subcolumns, new_subcolumns); } ColumnPtr ColumnObject::filter(const Filter& filter, ssize_t count) const { - DCHECK(is_finalized()); - auto new_column = ColumnObject::create(true); + if (!is_finalized()) { + const_cast(this)->finalize(); + } + auto new_column = ColumnObject::create(true, false); for (auto& entry : subcolumns) { auto subcolumn = entry->data.get_finalized_column().filter(filter, count); - new_column->add_sub_column(entry->path, std::move(subcolumn)); + new_column->add_sub_column(entry->path, subcolumn->assume_mutable(), + entry->data.get_least_common_type()); } return new_column; } +Status ColumnObject::filter_by_selector(const uint16_t* sel, size_t sel_size, IColumn* col_ptr) { + if (!is_finalized()) { + finalize(); + } + auto* res = assert_cast(col_ptr); + for (const auto& subcolumn : subcolumns) { + auto new_subcolumn = subcolumn->data.get_least_common_type()->create_column(); + RETURN_IF_ERROR(subcolumn->data.get_finalized_column().filter_by_selector( + sel, sel_size, new_subcolumn.get())); + res->add_sub_column(subcolumn->path, new_subcolumn->assume_mutable(), + subcolumn->data.get_least_common_type()); + } + return Status::OK(); +} + size_t ColumnObject::filter(const Filter& filter) { - DCHECK(is_finalized()); + if (!is_finalized()) { + finalize(); + } + size_t count = filter.size() - simd::count_zero_num((int8_t*)filter.data(), filter.size()); + if (count == 0) { + for_each_subcolumn([](auto& part) { part->clear(); }); + } else { + for_each_subcolumn([&](auto& part) { + if (part->size() != count) { + if (part->is_exclusive()) { + const auto result_size = part->filter(filter); + if (result_size != count) { + throw Exception(ErrorCode::INTERNAL_ERROR, + "result_size not euqal with filter_size, result_size={}, " + "filter_size={}", + result_size, count); + } + CHECK_EQ(result_size, count); + } else { + part = part->filter(filter, count); + } + } + }); + } + num_rows = count; +#ifndef NDEBUG + check_consistency(); +#endif + return count; +} + +void ColumnObject::clear() { for (auto& entry : subcolumns) { - num_rows = entry->data.get_finalized_column().filter(filter); + for (auto& part : entry->data.data) { + part->clear(); + } + entry->data.num_of_defaults_in_prefix = 0; } - return num_rows; + num_rows = 0; } void ColumnObject::revise_to(int target_num_rows) { @@ -926,10 +1320,85 @@ void ColumnObject::revise_to(int target_num_rows) { num_rows = target_num_rows; } +void ColumnObject::create_root() { + auto type = is_nullable ? make_nullable(std::make_shared()) + : std::make_shared(); + add_sub_column({}, type->create_column(), type); +} + +void ColumnObject::create_root(const DataTypePtr& type, MutableColumnPtr&& column) { + if (num_rows == 0) { + num_rows = column->size(); + } + add_sub_column({}, std::move(column), type); +} + +bool ColumnObject::is_null_root() const { + auto* root = subcolumns.get_root(); + if (root == nullptr) { + return true; + } + if (root->data.num_of_defaults_in_prefix == 0 && + (root->data.data.empty() || is_nothing(root->data.get_least_common_type()))) { + return true; + } + return false; +} + +bool ColumnObject::is_scalar_variant() const { + // Only root itself + return !is_null_root() && subcolumns.get_leaves().size() == 1; +} + +DataTypePtr ColumnObject::get_root_type() const { + return subcolumns.get_root()->data.get_least_common_type(); +} + +#define SANITIZE_ROOT() \ + if (is_null_root()) { \ + return Status::InternalError("No root column, path {}", path.get_path()); \ + } \ + if (!WhichDataType(remove_nullable(subcolumns.get_root()->data.get_least_common_type())) \ + .is_json()) { \ + return Status::InternalError( \ + "Root column is not jsonb type but {}, path {}", \ + subcolumns.get_root()->data.get_least_common_type()->get_name(), path.get_path()); \ + } + +Status ColumnObject::extract_root(const PathInData& path) { + SANITIZE_ROOT(); + if (!path.empty()) { + MutableColumnPtr extracted; + RETURN_IF_ERROR(schema_util::extract(subcolumns.get_root()->data.get_finalized_column_ptr(), + path, extracted)); + subcolumns.get_mutable_root()->data.data[0] = extracted->get_ptr(); + } + return Status::OK(); +} + +Status ColumnObject::extract_root(const PathInData& path, MutableColumnPtr& dst) const { + SANITIZE_ROOT(); + if (!path.empty()) { + RETURN_IF_ERROR(schema_util::extract(subcolumns.get_root()->data.get_finalized_column_ptr(), + path, dst)); + } else { + if (!dst) { + dst = subcolumns.get_root()->data.get_finalized_column_ptr()->clone_empty(); + dst->reserve(num_rows); + } + dst->insert_range_from(*subcolumns.get_root()->data.get_finalized_column_ptr(), 0, + num_rows); + } + return Status::OK(); +} + template void align_variant_by_name_and_type(ColumnObject& dst, const ColumnObject& src, size_t row_cnt, ColumnInserterFn inserter) { - CHECK(dst.is_finalized() && src.is_finalized()); + CHECK(dst.is_finalized()); + if (!src.is_finalized()) { + const_cast(src).finalize(); + } // Use rows() here instead of size(), since size() will check_consistency // but we could not check_consistency since num_rows will be upgraded even // if src and dst is empty, we just increase the num_rows of dst and fill @@ -940,6 +1409,10 @@ void align_variant_by_name_and_type(ColumnObject& dst, const ColumnObject& src, if (src_subcol == nullptr) { entry->data.get_finalized_column().insert_many_defaults(row_cnt); } else { + // It's the first time alignment, so that we should build it + if (entry->data.get_least_common_type()->get_type_id() == TypeIndex::Nothing) { + entry->data.add_new_column_part(src_subcol->get_least_common_type()); + } // TODO handle type confict here, like ColumnObject before CHECK(entry->data.get_least_common_type()->equals( *src_subcol->get_least_common_type())); @@ -972,15 +1445,6 @@ void align_variant_by_name_and_type(ColumnObject& dst, const ColumnObject& src, #endif } -void ColumnObject::insert_range_from(const IColumn& src, size_t start, size_t length) { - // insert_range_from with alignment - const ColumnObject& src_column = *check_and_get_column(src); - align_variant_by_name_and_type(*this, src_column, length, - [start, length](const IColumn& src, IColumn* dst) { - dst->insert_range_from(src, start, length); - }); -} - void ColumnObject::append_data_by_selector(MutableColumnPtr& res, const IColumn::Selector& selector) const { // append by selector with alignment diff --git a/be/src/vec/columns/column_object.h b/be/src/vec/columns/column_object.h index 6bff69b1e67ddc..cade1342b63afb 100644 --- a/be/src/vec/columns/column_object.h +++ b/be/src/vec/columns/column_object.h @@ -20,6 +20,8 @@ #pragma once #include +#include +#include #include #include @@ -39,7 +41,10 @@ #include "vec/core/field.h" #include "vec/core/types.h" #include "vec/data_types/data_type.h" +#include "vec/data_types/data_type_jsonb.h" #include "vec/data_types/data_type_nullable.h" +#include "vec/data_types/serde/data_type_serde.h" +#include "vec/io/reader_buffer.h" #include "vec/json/path_in_data.h" class SipHash; @@ -82,13 +87,17 @@ class ColumnObject final : public COWHelper { * After insertion of all values subcolumn should be finalized * for writing and other operations. */ + + // Using jsonb type as most common type, since it's adopted all types of json + using MostCommonType = DataTypeJsonb; class Subcolumn { public: Subcolumn() = default; - Subcolumn(size_t size_, bool is_nullable_); + Subcolumn(size_t size_, bool is_nullable_, bool is_root = false); - Subcolumn(MutableColumnPtr&& data_, bool is_nullable_); + Subcolumn(MutableColumnPtr&& data_, DataTypePtr type, bool is_nullable_, + bool is_root = false); size_t size() const; @@ -100,7 +109,13 @@ class ColumnObject final : public COWHelper { const DataTypePtr& get_least_common_type() const { return least_common_type.get(); } - const DataTypePtr& get_least_common_typeBase() const { return least_common_type.getBase(); } + const DataTypePtr& get_least_common_typeBase() const { + return least_common_type.get_base(); + } + + const DataTypeSerDeSPtr& get_least_common_type_serde() const { + return least_common_type.get_serde(); + } size_t get_dimensions() const { return least_common_type.get_dimensions(); } @@ -126,12 +141,12 @@ class ColumnObject final : public COWHelper { /// creates a single column that stores all values. void finalize(); + bool check_if_sparse_column(size_t num_rows); + /// Returns last inserted field. Field get_last_field() const; - /// Recreates subcolumn with default scalar values and keeps sizes of arrays. - /// Used to create columns of type Nested with consistent array sizes. - Subcolumn recreate_with_default_values(const FieldInfo& field_info) const; + FieldInfo get_subcolumn_field_info() const; /// Returns single column if subcolumn in finalizes. /// Otherwise -- undefined behaviour. @@ -141,8 +156,12 @@ class ColumnObject final : public COWHelper { const ColumnPtr& get_finalized_column_ptr() const; + ColumnPtr& get_finalized_column_ptr(); + void remove_nullable(); + void add_new_column_part(DataTypePtr type); + friend class ColumnObject; private: @@ -154,18 +173,22 @@ class ColumnObject final : public COWHelper { const DataTypePtr& get() const { return type; } - const DataTypePtr& getBase() const { return base_type; } + const DataTypePtr& get_base() const { return base_type; } size_t get_dimensions() const { return num_dimensions; } void remove_nullable() { type = doris::vectorized::remove_nullable(type); } + const DataTypeSerDeSPtr& get_serde() const { return least_common_type_serder; } + private: DataTypePtr type; DataTypePtr base_type; size_t num_dimensions = 0; + DataTypeSerDeSPtr least_common_type_serder; }; - void add_new_column_part(DataTypePtr type); + + void wrapp_array_nullable(); /// Current least common type of all values inserted to this subcolumn. LeastCommonType least_common_type; @@ -176,10 +199,14 @@ class ColumnObject final : public COWHelper { /// That means that the least common type for i-th prefix is the type of i-th part /// and it's the supertype for all type of column from 0 to i-1. std::vector data; + std::vector data_types; /// Until we insert any non-default field we don't know further /// least common type and we count number of defaults in prefix, /// which will be converted to the default type of final common type. size_t num_of_defaults_in_prefix = 0; + // If it is the root subcolumn of SubcolumnsTree, + // the root Node should be JSONB type when finalize + bool is_root = false; }; using Subcolumns = SubcolumnsTree; @@ -188,23 +215,66 @@ class ColumnObject final : public COWHelper { const bool is_nullable; Subcolumns subcolumns; size_t num_rows; + // sparse columns will be merge and encoded into root column + Subcolumns sparse_columns; + // The rapidjson document format of Subcolumns tree structure + // the leaves is null.In order to display whole document, copy + // this structure and fill with Subcolumns sub items + mutable std::shared_ptr doc_structure; public: static constexpr auto COLUMN_NAME_DUMMY = "_dummy"; - explicit ColumnObject(bool is_nullable_); + explicit ColumnObject(bool is_nullable_, bool create_root = true); ColumnObject(Subcolumns&& subcolumns_, bool is_nullable_); ~ColumnObject() override = default; - bool can_be_inside_nullable() const override { return true; } - /// Checks that all subcolumns have consistent sizes. void check_consistency() const; + MutableColumnPtr get_root() { + if (subcolumns.empty() || is_nothing(subcolumns.get_root()->data.get_least_common_type())) { + return nullptr; + } + return subcolumns.get_mutable_root()->data.get_finalized_column_ptr()->assume_mutable(); + } + + bool serialize_one_row_to_string(int row, std::string* output) const; + + bool serialize_one_row_to_string(int row, BufferWritable& output) const; + + // serialize one row to json format + bool serialize_one_row_to_json_format(int row, rapidjson::StringBuffer* output, + bool* is_null) const; + + // merge multiple sub sparse columns into root + void merge_sparse_to_root_column(); + + // ensure root node is a certain type + void ensure_root_node_type(const DataTypePtr& type); + + // create jsonb root if missing + void create_root(); + + // create root with type and column if missing + void create_root(const DataTypePtr& type, MutableColumnPtr&& column); + + // root is null or type nothing + bool is_null_root() const; + + // Only single scalar root column + bool is_scalar_variant() const; + + ColumnPtr get_root() const { return subcolumns.get_root()->data.get_finalized_column_ptr(); } + bool has_subcolumn(const PathInData& key) const; + DataTypePtr get_root_type() const; + + bool is_variant() const override { return true; } + // return null if not found const Subcolumn* get_subcolumn(const PathInData& key) const; @@ -226,15 +296,11 @@ class ColumnObject final : public COWHelper { size_t rows() const { return num_rows; } /// Adds a subcolumn from existing IColumn. - bool add_sub_column(const PathInData& key, MutableColumnPtr&& subcolumn); + bool add_sub_column(const PathInData& key, MutableColumnPtr&& subcolumn, DataTypePtr type); /// Adds a subcolumn of specific size with default values. bool add_sub_column(const PathInData& key, size_t new_size); - /// Adds a subcolumn of type Nested of specific size with default values. - /// It cares about consistency of sizes of Nested arrays. - bool add_nested_subcolumn(const PathInData& key, const FieldInfo& field_info, size_t new_size); - const Subcolumns& get_subcolumns() const { return subcolumns; } Subcolumns& get_subcolumns() { return subcolumns; } @@ -258,11 +324,21 @@ class ColumnObject final : public COWHelper { void remove_subcolumns(const std::unordered_set& keys); + void finalize(bool ignore_sparse); + /// Finalizes all subcolumns. - void finalize(); + void finalize() override; bool is_finalized() const; + MutableColumnPtr clone_finalized() const { + auto finalized = IColumn::mutate(get_ptr()); + static_cast(finalized.get())->finalize(); + return finalized; + } + + void clear() override; + /// Part of interface const char* get_family_name() const override { return "Variant"; } @@ -279,8 +355,6 @@ class ColumnObject final : public COWHelper { // Do nothing, call try_insert instead void insert(const Field& field) override { try_insert(field); } - void insert_range_from(const IColumn& src, size_t start, size_t length) override; - void append_data_by_selector(MutableColumnPtr& res, const IColumn::Selector& selector) const override; @@ -290,18 +364,16 @@ class ColumnObject final : public COWHelper { // May throw execption void try_insert(const Field& field); - void try_insert_from(const IColumn& src, size_t n); + void insert_from(const IColumn& src, size_t n) override; - void try_insert_range_from(const IColumn& src, size_t start, size_t length); + void insert_range_from(const IColumn& src, size_t start, size_t length) override; void insert_default() override; // Revise this column to specified num_rows void revise_to(int num_rows); - [[noreturn]] ColumnPtr replicate(const Offsets& offsets) const override { - LOG(FATAL) << "should not call the method replicate in column object"; - } + ColumnPtr replicate(const Offsets& offsets) const override; void pop_back(size_t length) override; @@ -339,12 +411,11 @@ class ColumnObject final : public COWHelper { ColumnPtr filter(const Filter&, ssize_t) const override; + Status filter_by_selector(const uint16_t* sel, size_t sel_size, IColumn* col_ptr) override; + size_t filter(const Filter&) override; - ColumnPtr permute(const Permutation&, size_t) const override { - LOG(FATAL) << "should not call the method in column object"; - return nullptr; - } + ColumnPtr permute(const Permutation&, size_t) const override; int compare_at(size_t n, size_t m, const IColumn& rhs, int nan_direction_hint) const override { LOG(FATAL) << "should not call the method in column object"; @@ -378,10 +449,17 @@ class ColumnObject final : public COWHelper { } template - ColumnPtr apply_for_subcolumns(Func&& func, std::string_view func_name) const; + MutableColumnPtr apply_for_subcolumns(Func&& func) const; ColumnPtr index(const IColumn& indexes, size_t limit) const override; + // Extract path from root column and replace root with new extracted column, + // root must be jsonb type + Status extract_root(const PathInData& path); + + // Extract path from root column and output to dst + Status extract_root(const PathInData& path, MutableColumnPtr& dst) const; + void strip_outer_array(); bool empty() const; diff --git a/be/src/vec/columns/column_set.h b/be/src/vec/columns/column_set.h new file mode 100644 index 00000000000000..3b330f82284838 --- /dev/null +++ b/be/src/vec/columns/column_set.h @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// This file is copied from +// https://github.com/ClickHouse/ClickHouse/blob/master/src/Columns/ColumnSet.h +// and modified by Doris + +#pragma once + +#include "exprs/hybrid_set.h" +#include "vec/columns/column_dummy.h" + +namespace doris::vectorized { + +using ConstSetPtr = std::shared_ptr; + +/** A column containing multiple values in the `IN` section. + * Behaves like a constant-column (because the set is one, not its own for each line). + * This column has a nonstandard value, so it can not be obtained via a normal interface. + */ +class ColumnSet final : public COWHelper { +public: + friend class COWHelper; + + ColumnSet(size_t s_, const ConstSetPtr& data_) : data(data_) { s = s_; } + ColumnSet(const ColumnSet&) = default; + + const char* get_family_name() const override { return "Set"; } + MutableColumnPtr clone_dummy(size_t s_) const override { return ColumnSet::create(s_, data); } + + ConstSetPtr get_data() const { return data; } + +private: + ConstSetPtr data; +}; + +} // namespace doris::vectorized \ No newline at end of file diff --git a/be/src/vec/columns/column_string.cpp b/be/src/vec/columns/column_string.cpp index 5d5abd64349ecb..d6a3a514994067 100644 --- a/be/src/vec/columns/column_string.cpp +++ b/be/src/vec/columns/column_string.cpp @@ -207,6 +207,19 @@ size_t ColumnString::filter(const Filter& filter) { return filter_arrays_impl(chars, offsets, filter); } +Status ColumnString::filter_by_selector(const uint16_t* sel, size_t sel_size, IColumn* col_ptr) { + auto* col = static_cast(col_ptr); + Chars& res_chars = col->chars; + Offsets& res_offsets = col->offsets; + Filter filter; + filter.resize_fill(offsets.size(), 0); + for (size_t i = 0; i < sel_size; i++) { + filter[sel[i]] = 1; + } + filter_arrays_impl(chars, offsets, res_chars, res_offsets, filter, sel_size); + return Status::OK(); +} + ColumnPtr ColumnString::permute(const Permutation& perm, size_t limit) const { size_t size = offsets.size(); diff --git a/be/src/vec/columns/column_string.h b/be/src/vec/columns/column_string.h index ae2bb9d25f98f1..5c2d849428119f 100644 --- a/be/src/vec/columns/column_string.h +++ b/be/src/vec/columns/column_string.h @@ -129,6 +129,11 @@ class ColumnString final : public COWHelper { void get(size_t n, Field& res) const override { assert(n < size()); + if (res.get_type() == Field::Types::JSONB) { + // Handle JsonbField + res = JsonbField(reinterpret_cast(&chars[offset_at(n)]), size_at(n)); + return; + } res.assign_string(&chars[offset_at(n)], size_at(n)); } @@ -138,15 +143,23 @@ class ColumnString final : public COWHelper { } void insert(const Field& x) override { - const String& s = vectorized::get(x); + StringRef s; + if (x.get_type() == Field::Types::JSONB) { + // Handle JsonbField + const auto& real_field = vectorized::get(x); + s = StringRef(real_field.get_value(), real_field.get_size()); + } else { + s.data = vectorized::get(x).data(); + s.size = vectorized::get(x).size(); + } const size_t old_size = chars.size(); - const size_t size_to_append = s.size(); + const size_t size_to_append = s.size; const size_t new_size = old_size + size_to_append; check_chars_length(new_size, old_size + 1); chars.resize(new_size); - memcpy(chars.data() + old_size, s.c_str(), size_to_append); + memcpy(chars.data() + old_size, s.data, size_to_append); offsets.push_back(new_size); } @@ -478,6 +491,8 @@ class ColumnString final : public COWHelper { ColumnPtr filter(const Filter& filt, ssize_t result_size_hint) const override; size_t filter(const Filter& filter) override; + Status filter_by_selector(const uint16_t* sel, size_t sel_size, IColumn* col_ptr) override; + ColumnPtr permute(const Permutation& perm, size_t limit) const override; void sort_column(const ColumnSorter* sorter, EqualFlags& flags, IColumn::Permutation& perms, @@ -523,8 +538,6 @@ class ColumnString final : public COWHelper { void resize(size_t n) override; - bool can_be_inside_nullable() const override { return true; } - bool is_column_string() const override { return true; } bool structure_equals(const IColumn& rhs) const override { @@ -589,6 +602,10 @@ class ColumnString final : public COWHelper { } ColumnPtr index(const IColumn& indexes, size_t limit) const override; + + double get_ratio_of_default_rows(double sample_ratio) const override { + return get_ratio_of_default_rows_impl(sample_ratio); + } }; } // namespace doris::vectorized diff --git a/be/src/vec/columns/column_struct.h b/be/src/vec/columns/column_struct.h index 36854824198dd2..919b971b5ac5fa 100644 --- a/be/src/vec/columns/column_struct.h +++ b/be/src/vec/columns/column_struct.h @@ -84,7 +84,6 @@ class ColumnStruct final : public COWHelper { std::string get_name() const override; bool is_column_struct() const override { return true; } const char* get_family_name() const override { return "Struct"; } - bool can_be_inside_nullable() const override { return true; } MutableColumnPtr clone_empty() const override; MutableColumnPtr clone_resized(size_t size) const override; size_t size() const override { return columns.at(0)->size(); } diff --git a/be/src/vec/columns/column_vector.h b/be/src/vec/columns/column_vector.h index 85d64740d19161..f3cfbb65142189 100644 --- a/be/src/vec/columns/column_vector.h +++ b/be/src/vec/columns/column_vector.h @@ -412,6 +412,10 @@ class ColumnVector final : public COWHelper> template ColumnPtr index_impl(const PaddedPODArray& indexes, size_t limit) const; + double get_ratio_of_default_rows(double sample_ratio) const override { + return this->template get_ratio_of_default_rows_impl(sample_ratio); + } + ColumnPtr replicate(const IColumn::Offsets& offsets) const override; void replicate(const uint32_t* indexs, size_t target_size, IColumn& column) const override; @@ -428,8 +432,6 @@ class ColumnVector final : public COWHelper> // void gather(ColumnGathererStream & gatherer_stream) override; - bool can_be_inside_nullable() const override { return true; } - bool is_fixed_and_contiguous() const override { return true; } size_t size_of_value_if_fixed() const override { return sizeof(T); } StringRef get_raw_data() const override { diff --git a/be/src/vec/columns/predicate_column.h b/be/src/vec/columns/predicate_column.h index 3aec3b1540f229..87d1993e2747e2 100644 --- a/be/src/vec/columns/predicate_column.h +++ b/be/src/vec/columns/predicate_column.h @@ -137,8 +137,6 @@ class PredicateColumnType final : public COWHelper::get(); } - [[noreturn]] MutableColumnPtr clone_resized(size_t size) const override { - LOG(FATAL) << "clone_resized not supported in PredicateColumnType"; + MutableColumnPtr clone_resized(size_t size) const override { + DCHECK(size == 0); + return this->create(); } void insert(const Field& x) override { @@ -401,8 +400,6 @@ class PredicateColumnType final : public COWHelper class SubcolumnsTree { public: struct Node { - enum Kind { - TUPLE, - NESTED, - SCALAR, - }; + enum Kind { TUPLE, NESTED, SCALAR }; explicit Node(Kind kind_) : kind(kind_) {} Node(Kind kind_, const NodeData& data_) : kind(kind_), data(data_) {} Node(Kind kind_, const NodeData& data_, const PathInData& path_) : kind(kind_), data(data_), path(path_) {} + Node(Kind kind_, NodeData&& data_) : kind(kind_), data(std::move(data_)) {} + Node(Kind kind_, NodeData&& data_, const PathInData& path_) + : kind(kind_), data(std::move(data_)), path(path_) {} Kind kind = TUPLE; const Node* parent = nullptr; @@ -53,6 +52,20 @@ class SubcolumnsTree { bool is_nested() const { return kind == NESTED; } bool is_scalar() const { return kind == SCALAR; } + bool is_scalar_without_children() const { return kind == SCALAR && children.empty(); } + + // Only modify data and kind + void modify(std::shared_ptr&& other) { + data = std::move(other->data); + kind = other->kind; + path = other->path; + } + + // modify data and kind + void modify_to_scalar(NodeData&& other_data) { + data = std::move(other_data); + kind = Kind::SCALAR; + } void add_child(std::string_view key, std::shared_ptr next_node) { next_node->parent = this; @@ -79,10 +92,30 @@ class SubcolumnsTree { }); } + bool add(const PathInData& path, NodeData&& leaf_data) { + return add(path, [&](NodeKind kind, bool exists) -> NodePtr { + if (exists) { + return nullptr; + } + + if (kind == Node::SCALAR) { + return std::make_shared(kind, std::move(leaf_data), path); + } + + return std::make_shared(kind); + }); + } + /// Callback for creation of node. Receives kind of node and /// flag, which is true if node already exists. using NodeCreator = std::function; + // create root as SCALAR node + void create_root(const NodeData& leaf_data) { + root = std::make_shared(Node::SCALAR, leaf_data); + leaves.push_back(root); + } + bool add(const PathInData& path, const NodeCreator& node_creator) { const auto& parts = path.get_parts(); @@ -96,8 +129,6 @@ class SubcolumnsTree { Node* current_node = root.get(); for (size_t i = 0; i < parts.size() - 1; ++i) { - // assert(current_node->kind != Node::SCALAR); - auto it = current_node->children.find( StringRef {parts[i].key.data(), parts[i].key.size()}); if (it != current_node->children.end()) { @@ -118,7 +149,11 @@ class SubcolumnsTree { auto it = current_node->children.find( StringRef {parts.back().key.data(), parts.back().key.size()}); if (it != current_node->children.end()) { - return false; + // Modify this node to Node::SCALAR + auto new_node = node_creator(Node::SCALAR, false); + it->get_second()->modify(std::move(new_node)); + leaves.push_back(it->get_second()); + return true; } auto next_node = node_creator(Node::SCALAR, false); @@ -183,6 +218,19 @@ class SubcolumnsTree { const Nodes& get_leaves() const { return leaves; } const Node* get_root() const { return root.get(); } + Node* get_mutable_root() { return root.get(); } + + static void get_leaves_of_node(const Node* node, std::vector& nodes, + vectorized::PathsInData& paths) { + if (node->is_scalar()) { + nodes.push_back(node); + paths.push_back(node->path); + } + for (auto it = node->children.begin(); it != node->children.end(); ++it) { + auto child = it->get_second(); + get_leaves_of_node(child.get(), nodes, paths); + } + } using iterator = typename Nodes::iterator; using const_iterator = typename Nodes::const_iterator; diff --git a/be/src/vec/common/field_visitors.h b/be/src/vec/common/field_visitors.h index 8434483b7721ea..2066a94960a3d5 100644 --- a/be/src/vec/common/field_visitors.h +++ b/be/src/vec/common/field_visitors.h @@ -65,6 +65,8 @@ typename std::decay_t::ResultType apply_visitor(Visitor&& visitor, F&& return visitor(field.template get>()); case Field::Types::Decimal256: return visitor(field.template get>()); + case Field::Types::JSONB: + return visitor(field.template get()); default: LOG(FATAL) << "Bad type of Field"; return {}; diff --git a/be/src/vec/common/schema_util.cpp b/be/src/vec/common/schema_util.cpp index c18ec7aa221e06..42167b6b8c3be0 100644 --- a/be/src/vec/common/schema_util.cpp +++ b/be/src/vec/common/schema_util.cpp @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include #include @@ -36,16 +39,17 @@ #include "common/config.h" #include "common/status.h" +#include "exprs/json_functions.h" #include "olap/olap_common.h" +#include "olap/tablet_schema.h" #include "runtime/client_cache.h" #include "runtime/exec_env.h" -#include "runtime/types.h" #include "udf/udf.h" -#include "util/string_util.h" -#include "util/thrift_rpc_helper.h" #include "vec/columns/column.h" #include "vec/columns/column_array.h" +#include "vec/columns/column_nullable.h" #include "vec/columns/column_object.h" +#include "vec/columns/columns_number.h" #include "vec/common/assert_cast.h" #include "vec/common/typeid_cast.h" #include "vec/core/block.h" @@ -55,9 +59,15 @@ #include "vec/core/types.h" #include "vec/data_types/data_type.h" #include "vec/data_types/data_type_array.h" +#include "vec/data_types/data_type_factory.hpp" +#include "vec/data_types/data_type_jsonb.h" #include "vec/data_types/data_type_nullable.h" +#include "vec/data_types/data_type_object.h" +#include "vec/data_types/data_type_string.h" +#include "vec/data_types/get_least_supertype.h" #include "vec/functions/function.h" #include "vec/functions/simple_function_factory.h" +#include "vec/json/parse2column.h" #include "vec/json/path_in_data.h" namespace doris::vectorized::schema_util { @@ -129,164 +139,254 @@ bool is_conversion_required_between_integers(FieldType lhs, FieldType rhs) { return true; } -Status cast_column(const ColumnWithTypeAndName& arg, const DataTypePtr& type, ColumnPtr* result, - RuntimeState* state) { - ColumnsWithTypeAndName arguments; - if (WhichDataType(type->get_type_id()).is_string()) { - // Special handle ColumnString, since the original cast logic use ColumnString's first item - // as the name of the dest type - arguments = {arg, {type->create_column_const(1, type->get_name()), type, ""}}; - } else { - arguments = {arg, {type->create_column_const_with_default_value(1), type, ""}}; - } +Status cast_column(const ColumnWithTypeAndName& arg, const DataTypePtr& type, ColumnPtr* result) { + ColumnsWithTypeAndName arguments { + arg, {type->create_column_const_with_default_value(1), type, type->get_name()}}; auto function = SimpleFunctionFactory::instance().get_function("CAST", arguments, type); + if (!function) { + return Status::InternalError("Not found cast function {} to {}", arg.type->get_name(), + type->get_name()); + } Block tmp_block {arguments}; - // the 0 position is input argument, the 1 position is to type argument, the 2 position is result argument vectorized::ColumnNumbers argnum; argnum.emplace_back(0); argnum.emplace_back(1); size_t result_column = tmp_block.columns(); + auto ctx = FunctionContext::create_context(nullptr, {}, {}); + // We convert column string to jsonb type just add a string jsonb field to dst column instead of parse + // each line in original string column. + ctx->set_string_as_jsonb_string(true); tmp_block.insert({nullptr, type, arg.name}); - auto need_state_only = FunctionContext::create_context(state, {}, {}); - RETURN_IF_ERROR(function->execute(need_state_only.get(), tmp_block, argnum, result_column, - arg.column->size())); + RETURN_IF_ERROR( + function->execute(ctx.get(), tmp_block, argnum, result_column, arg.column->size())); *result = std::move(tmp_block.get_by_position(result_column).column); + // Variant column is a really special case, src type is nullable but dst variant type is none nullable, + // but we still need to wrap nullmap into variant root column to prevent from nullable info lost. + // TODO rethink and better handle this sepecial situation + if (arg.type->is_nullable() && WhichDataType(type).is_variant_type()) { + auto variant = ColumnObject::create(true); + auto& old_variant = assert_cast(*(*result)->assume_mutable()); + DCHECK(!old_variant.get_root()->is_nullable()); + auto nullable = ColumnNullable::create( + old_variant.get_root(), + assert_cast(*arg.column).get_null_map_column_ptr()); + variant->create_root(make_nullable(arg.type), nullable->assume_mutable()); + *result = std::move(variant); + } return Status::OK(); } -// send an empty add columns rpc, the rpc response will fill with base schema info -// maybe we could seperate this rpc from add columns rpc -Status send_fetch_full_base_schema_view_rpc(FullBaseSchemaView* schema_view) { - TAddColumnsRequest req; - TAddColumnsResult res; - TTabletInfo tablet_info; - req.__set_table_name(schema_view->table_name); - req.__set_db_name(schema_view->db_name); - req.__set_table_id(schema_view->table_id); - // Set empty columns - req.__set_addColumns({}); - auto master_addr = ExecEnv::GetInstance()->master_info()->network_address; - Status rpc_st = ThriftRpcHelper::rpc( - master_addr.hostname, master_addr.port, - [&req, &res](FrontendServiceConnection& client) { client->addColumns(res, req); }, - config::txn_commit_rpc_timeout_ms); - if (!rpc_st.ok()) { - return Status::InternalError("Failed to fetch schema info, encounter rpc failure"); +void get_column_by_type(const vectorized::DataTypePtr& data_type, const std::string& name, + TabletColumn& column, const ExtraInfo& ext_info) { + column.set_name(name); + column.set_type(data_type->get_storage_field_type()); + if (ext_info.unique_id >= 0) { + column.set_unique_id(ext_info.unique_id); } - // TODO(lhy) handle more status code - if (res.status.status_code != TStatusCode::OK) { - LOG(WARNING) << "failed to fetch schema info, code:" << res.status.status_code - << ", msg:" << res.status.error_msgs[0]; - return Status::InvalidArgument( - fmt::format("Failed to fetch schema info, {}", res.status.error_msgs[0])); + if (ext_info.parent_unique_id >= 0) { + column.set_parent_unique_id(ext_info.parent_unique_id); } - for (const auto& column : res.allColumns) { - schema_view->column_name_to_column[column.column_name] = column; + if (!ext_info.path_info.empty()) { + column.set_path_info(ext_info.path_info); } - schema_view->schema_version = res.schema_version; - return Status::OK(); + if (data_type->is_nullable()) { + const auto& real_type = static_cast(*data_type); + column.set_is_nullable(true); + get_column_by_type(real_type.get_nested_type(), name, column, {}); + return; + } + if (data_type->get_type_id() == TypeIndex::Array) { + TabletColumn child; + get_column_by_type(assert_cast(data_type.get())->get_nested_type(), + "", child, {}); + column.set_length(TabletColumn::get_field_length_by_type( + data_type->get_type_as_tprimitive_type(), 0)); + column.add_sub_column(child); + column.set_default_value("[]"); + return; + } + // size is not fixed when type is string or json + if (WhichDataType(*data_type).is_string() || WhichDataType(*data_type).is_json()) { + return; + } + if (WhichDataType(*data_type).is_simple()) { + column.set_length(data_type->get_size_of_value_in_memory()); + return; + } + // TODO handle more types like struct/date/datetime/decimal... + __builtin_unreachable(); } -static const std::regex COLUMN_NAME_REGEX( - "^[_a-zA-Z@0-9\\s<>/][.a-zA-Z0-9_+-/>assume_mutable(); - auto* column_object_ptr = assert_cast(dynamic_col.get()); - if (column_object_ptr->empty()) { - return Status::OK(); +TabletColumn get_least_type_column(const TabletColumn& original, const DataTypePtr& new_type, + const ExtraInfo& ext_info, bool* changed) { + TabletColumn result_column; + vectorized::DataTypePtr original_type = original.get_vec_type(); + vectorized::DataTypePtr common_type; + vectorized::get_least_supertype( + vectorized::DataTypes {original_type, new_type}, &common_type); + if (!original_type->equals(*common_type)) { + // update to common type + *changed = true; + vectorized::schema_util::get_column_by_type(common_type, original.name(), result_column, + ext_info); + } else { + *changed = false; + result_column = original; + result_column.set_parent_unique_id(ext_info.parent_unique_id); + result_column.set_unique_id(ext_info.unique_id); + result_column.set_path_info(ext_info.path_info); } - size_t num_rows = column_object_ptr->size(); - CHECK(block.rows() <= num_rows); - CHECK(column_object_ptr->is_finalized()); - Columns subcolumns; - DataTypes types; - std::vector names; - std::unordered_set static_column_names; + return result_column; +} - // extract columns from dynamic column - for (auto& subcolumn : column_object_ptr->get_subcolumns()) { - subcolumns.push_back(subcolumn->data.get_finalized_column().get_ptr()); - types.push_back(subcolumn->data.get_least_common_type()); - names.push_back(subcolumn->path.get_path()); - } - for (size_t i = 0; i < subcolumns.size(); ++i) { - // Block may already contains this column, eg. key columns, we should ignore - // or replcace the same column from object subcolumn - ColumnWithTypeAndName* column_type_name = block.try_get_by_name(names[i]); - if (column_type_name) { - ColumnPtr column = subcolumns[i]; - DataTypePtr dst_type = column_type_name->type; - // Make it nullable when src is nullable but dst is not - // since we should filter some data when slot type is not null - // but column contains nulls - if (!dst_type->is_nullable() && column->is_nullable()) { - dst_type = make_nullable(dst_type); +void update_least_common_schema(const std::vector& schemas, + TabletSchemaSPtr& common_schema, int32_t variant_col_unique_id) { + // Types of subcolumns by path from all tuples. + std::unordered_map subcolumns_types; + for (const TabletSchemaSPtr& schema : schemas) { + for (const TabletColumn& col : schema->columns()) { + // Get subcolumns of this variant + if (!col.path_info().empty() && col.parent_unique_id() > 0 && + col.parent_unique_id() == variant_col_unique_id) { + subcolumns_types[col.path_info()].push_back( + DataTypeFactory::instance().create_data_type(col, col.is_nullable())); } - if (cast_to_original_type && !dst_type->equals(*types[i])) { - // Cast static columns to original slot type - RETURN_IF_ERROR(schema_util::cast_column({subcolumns[i], types[i], ""}, dst_type, - &column, state)); + } + } + PathsInData tuple_paths; + DataTypes tuple_types; + // Get the least common type for all paths. + for (const auto& [key, subtypes] : subcolumns_types) { + assert(!subtypes.empty()); + if (key.get_path() == ColumnObject::COLUMN_NAME_DUMMY) { + continue; + } + size_t first_dim = get_number_of_dimensions(*subtypes[0]); + tuple_paths.emplace_back(key); + for (size_t i = 1; i < subtypes.size(); ++i) { + if (first_dim != get_number_of_dimensions(*subtypes[i])) { + tuple_types.emplace_back(make_nullable(std::make_shared())); + LOG(INFO) << fmt::format( + "Uncompatible types of subcolumn '{}': {} and {}, cast to JSONB", + key.get_path(), subtypes[0]->get_name(), subtypes[i]->get_name()); + break; } - // replace original column - column_type_name->column = column; - column_type_name->type = dst_type; - static_column_names.emplace(names[i]); } + if (tuple_paths.size() == tuple_types.size()) { + continue; + } + DataTypePtr common_type; + get_least_supertype(subtypes, &common_type); + if (!common_type->is_nullable()) { + common_type = make_nullable(common_type); + } + tuple_types.emplace_back(common_type); } + CHECK_EQ(tuple_paths.size(), tuple_types.size()); - // Remove static ones remain extra dynamic columns - column_object_ptr->remove_subcolumns(static_column_names); + std::string variant_col_name = common_schema->column_by_uid(variant_col_unique_id).name(); + // Append all common type columns of this variant + for (int i = 0; i < tuple_paths.size(); ++i) { + TabletColumn common_column; + // const std::string& column_name = variant_col_name + "." + tuple_paths[i].get_path(); + get_column_by_type(tuple_types[i], tuple_paths[i].get_path(), common_column, + ExtraInfo {.unique_id = -1, + .parent_unique_id = variant_col_unique_id, + .path_info = tuple_paths[i]}); + common_schema->append_column(common_column); + } +} - // Fill default value - for (auto& entry : block) { - if (entry.column->size() < num_rows) { - entry.column->assume_mutable()->insert_many_defaults(num_rows - entry.column->size()); +void get_least_common_schema(const std::vector& schemas, + TabletSchemaSPtr& common_schema) { + // Pick tablet schema with max schema version + const TabletSchemaSPtr base_schema = + *std::max_element(schemas.cbegin(), schemas.cend(), + [](const TabletSchemaSPtr a, const TabletSchemaSPtr b) { + return a->schema_version() < b->schema_version(); + }); + CHECK(base_schema); + CHECK(common_schema); + common_schema->copy_from(*base_schema); + // Merge columns from other schemas + common_schema->clear_columns(); + std::vector variant_column_unique_id; + // Get all columns without extracted columns and collect variant col unique id + for (const TabletColumn& col : base_schema->columns()) { + if (col.is_variant_type()) { + variant_column_unique_id.push_back(col.unique_id()); } - } -#ifndef NDEBUG - for (const auto& column_type_name : block) { - if (column_type_name.column->size() != num_rows) { - LOG(FATAL) << "unmatched column:" << column_type_name.name - << ", expeted rows:" << num_rows - << ", but meet:" << column_type_name.column->size(); + if (!col.is_extracted_column()) { + common_schema->append_column(col); } } -#endif - return Status::OK(); -} - -void LocalSchemaChangeRecorder::add_extended_columns(const TabletColumn& new_column, - int32_t schema_version) { - std::lock_guard lock(_lock); - _schema_version = std::max(_schema_version, schema_version); - auto it = _extended_columns.find(new_column.name()); - if (it != _extended_columns.end()) { - return; + for (int32_t unique_id : variant_column_unique_id) { + update_least_common_schema(schemas, common_schema, unique_id); } - _extended_columns.emplace_hint(it, new_column.name(), new_column); } -bool LocalSchemaChangeRecorder::has_extended_columns() { - std::lock_guard lock(_lock); - return !_extended_columns.empty(); +void parse_variant_columns(Block& block, const std::vector& variant_pos) { + for (int i = 0; i < variant_pos.size(); ++i) { + auto& column = block.get_by_position(variant_pos[i]).column; + const auto& root = *assert_cast(*column.get()).get_root(); + const auto& raw_json_column = + root.is_nullable() + ? static_cast( + static_cast(root).get_nested_column()) + : static_cast(root); + MutableColumnPtr variant_column = ColumnObject::create(true); + parse_json_to_variant(*variant_column.get(), raw_json_column); + block.get_by_position(variant_pos[i]).column = variant_column->get_ptr(); + block.get_by_position(variant_pos[i]).type = std::make_shared("json", true); + } } -std::map LocalSchemaChangeRecorder::copy_extended_columns() { - std::lock_guard lock(_lock); - return _extended_columns; +void finalize_variant_columns(Block& block, const std::vector& variant_pos, + bool ignore_sparse) { + for (int i = 0; i < variant_pos.size(); ++i) { + auto& column = assert_cast( + block.get_by_position(variant_pos[i]).column->assume_mutable_ref()); + column.finalize(ignore_sparse); + } } -const TabletColumn& LocalSchemaChangeRecorder::column(const std::string& col_name) { - std::lock_guard lock(_lock); - assert(_extended_columns.find(col_name) != _extended_columns.end()); - return _extended_columns[col_name]; +void encode_variant_sparse_subcolumns(Block& block, const std::vector& variant_pos) { + for (int i = 0; i < variant_pos.size(); ++i) { + auto& column = assert_cast( + block.get_by_position(variant_pos[i]).column->assume_mutable_ref()); + // Make sure the root node is jsonb storage type + auto expected_root_type = make_nullable(std::make_shared()); + column.ensure_root_node_type(expected_root_type); + column.merge_sparse_to_root_column(); + } } -int32_t LocalSchemaChangeRecorder::schema_version() { - std::lock_guard lock(_lock); - return _schema_version; +// --------------------------- +Status extract(ColumnPtr source, const PathInData& path, MutableColumnPtr& dst) { + auto type_string = std::make_shared(); + std::string jsonpath = path.to_jsonpath(); + bool is_nullable = source->is_nullable(); + auto json_type = is_nullable ? make_nullable(std::make_shared()) + : std::make_shared(); + ColumnsWithTypeAndName arguments { + {source, json_type, ""}, + {type_string->create_column_const(1, Field(jsonpath.data(), jsonpath.size())), + type_string, ""}}; + auto function = + SimpleFunctionFactory::instance().get_function("jsonb_extract", arguments, json_type); + if (!function) { + return Status::InternalError("Not found function jsonb_extract"); + } + Block tmp_block {arguments}; + vectorized::ColumnNumbers argnum; + argnum.emplace_back(0); + argnum.emplace_back(1); + size_t result_column = tmp_block.columns(); + tmp_block.insert({nullptr, json_type, ""}); + RETURN_IF_ERROR(function->execute(nullptr, tmp_block, argnum, result_column, source->size())); + dst = tmp_block.get_by_position(result_column).column->assume_mutable(); + return Status::OK(); } +// --------------------------- } // namespace doris::vectorized::schema_util diff --git a/be/src/vec/common/schema_util.h b/be/src/vec/common/schema_util.h index 634dae8339a8eb..bdf43adaacadc0 100644 --- a/be/src/vec/common/schema_util.h +++ b/be/src/vec/common/schema_util.h @@ -30,12 +30,14 @@ #include "olap/tablet_schema.h" #include "udf/udf.h" #include "vec/aggregate_functions/aggregate_function.h" +#include "vec/columns/column.h" +#include "vec/columns/column_object.h" #include "vec/core/columns_with_type_and_name.h" #include "vec/core/field.h" #include "vec/data_types/data_type.h" +#include "vec/json/path_in_data.h" namespace doris { -class LocalSchemaChangeRecorder; enum class FieldType; namespace vectorized { @@ -59,16 +61,7 @@ DataTypePtr get_base_type_of_array(const DataTypePtr& type); Array create_empty_array_field(size_t num_dimensions); // Cast column to dst type -Status cast_column(const ColumnWithTypeAndName& arg, const DataTypePtr& type, ColumnPtr* result, - RuntimeState* = nullptr); - -// Object column will be unfolded and if cast_to_original_type -// the original column in the block will be replaced with the subcolumn -// from object column and casted to the new type from slot_descs. -// Also if column in block is empty, it will be filled -// with num_rows of default values -Status unfold_object(size_t dynamic_col_position, Block& block, bool cast_to_original_type, - RuntimeState* = nullptr); +Status cast_column(const ColumnWithTypeAndName& arg, const DataTypePtr& type, ColumnPtr* result); /// If both of types are signed/unsigned integers and size of left field type /// is less than right type, we don't need to convert field, @@ -76,43 +69,39 @@ Status unfold_object(size_t dynamic_col_position, Block& block, bool cast_to_ori bool is_conversion_required_between_integers(const IDataType& lhs, const IDataType& rhs); bool is_conversion_required_between_integers(FieldType lhs, FieldType rhs); -// Align block schema with tablet schema -// eg. -// Block: col1(int), col2(string) -// Schema: col1(double), col3(date) -// 1. col1(int) in block which type missmatch with schema col1 will be converted to double -// 2. col2 in block which missing in current schema will launch a schema change rpc -// 3. col3 in schema which missing in block will be ignored -// After schema changed, schame change history will add new columns -Status align_block_with_schema(const TabletSchema& schema, int64_t table_id /*for schema change*/, - Block& block, LocalSchemaChangeRecorder* history); -// record base schema column infos -// maybe use col_unique_id as key in the future -// but for dynamic table, column name if ok -struct FullBaseSchemaView { - ENABLE_FACTORY_CREATOR(FullBaseSchemaView); - phmap::flat_hash_map column_name_to_column; - int32_t schema_version = -1; - int32_t table_id = 0; - std::string table_name; - std::string db_name; -}; - -Status send_fetch_full_base_schema_view_rpc(FullBaseSchemaView* schema_view); - -// For tracking local schema change during load procedure -class LocalSchemaChangeRecorder { -public: - void add_extended_columns(const TabletColumn& new_column, int32_t schema_version); - bool has_extended_columns(); - std::map copy_extended_columns(); - const TabletColumn& column(const std::string& col_name); - int32_t schema_version(); - -private: - std::mutex _lock; - int32_t _schema_version = -1; - std::map _extended_columns; +struct ExtraInfo { + // -1 indicates it's not a Frontend generated column + int32_t unique_id = -1; + int32_t parent_unique_id = -1; + vectorized::PathInData path_info; }; +void get_column_by_type(const vectorized::DataTypePtr& data_type, const std::string& name, + TabletColumn& column, const ExtraInfo& ext_info); + +TabletColumn get_least_type_column(const TabletColumn& original, const DataTypePtr& new_type, + const ExtraInfo& ext_info, bool* changed); + +// Two steps to parse variant columns into flatterned columns +// 1. parse variant from raw json string +// 2. finalize variant column to each subcolumn least commn types, default ignore sparse sub columns +// 2. encode sparse sub columns +void parse_variant_columns(Block& block, const std::vector& variant_pos); +void finalize_variant_columns(Block& block, const std::vector& variant_pos, + bool ignore_sparse = true); +void encode_variant_sparse_subcolumns(Block& block, const std::vector& variant_pos); + +// Pick the tablet schema with the highest schema version as the reference. +// Then update all variant columns to there least common types. +// Return the final merged schema as common schema +void get_least_common_schema(const std::vector& schemas, + TabletSchemaSPtr& common_schema); + +// Get least common types for extracted columns which has Path info, +// with a speicified variant column's unique id +void update_least_common_schema(const std::vector& schemas, + TabletSchemaSPtr& common_schema, int32_t variant_col_unique_id); + +// Extract json data from source with path +Status extract(ColumnPtr source, const PathInData& path, MutableColumnPtr& dst); } // namespace doris::vectorized::schema_util diff --git a/be/src/vec/core/field.h b/be/src/vec/core/field.h index 6b9a2fc3523dc4..026de2d54e18a1 100644 --- a/be/src/vec/core/field.h +++ b/be/src/vec/core/field.h @@ -604,40 +604,6 @@ class Field { } } -private: - std::aligned_union_t, DecimalField, DecimalField, - DecimalField, DecimalField, BitmapValue, - HyperLogLog, QuantileState> - storage; - - Types::Which which; - - /// Assuming there was no allocated state or it was deallocated (see destroy). - template - void create_concrete(T&& x) { - using UnqualifiedType = std::decay_t; - - // In both Field and PODArray, small types may be stored as wider types, - // e.g. char is stored as UInt64. Field can return this extended value - // with get(). To avoid uninitialized results from get(), - // we must initialize the entire wide stored type, and not just the - // nominal type. - using StorageType = NearestFieldType; - new (&storage) StorageType(std::forward(x)); - which = TypeToEnum::value; - } - - /// Assuming same types. - template - void assign_concrete(T&& x) { - using JustT = std::decay_t; - assert(which == TypeToEnum::value); - JustT* MAY_ALIAS ptr = reinterpret_cast(&storage); - *ptr = std::forward(x); - } - template /// Field template parameter may be const or non-const Field. static void dispatch(F&& f, Field& field) { @@ -708,6 +674,41 @@ class Field { } } +private: + std::aligned_union_t, DecimalField, DecimalField, + DecimalField, DecimalField, BitmapValue, + HyperLogLog, QuantileState> + storage; + + Types::Which which; + + /// Assuming there was no allocated state or it was deallocated (see destroy). + template + void create_concrete(T&& x) { + using UnqualifiedType = std::decay_t; + + // In both Field and PODArray, small types may be stored as wider types, + // e.g. char is stored as UInt64. Field can return this extended value + // with get(). To avoid uninitialized results from get(), + // we must initialize the entire wide stored type, and not just the + // nominal type. + using StorageType = NearestFieldType; + new (&storage) StorageType(std::forward(x)); + which = TypeToEnum::value; + } + + /// Assuming same types. + template + void assign_concrete(T&& x) { + using JustT = std::decay_t; + assert(which == TypeToEnum::value); + JustT* MAY_ALIAS ptr = reinterpret_cast(&storage); + *ptr = std::forward(x); + } + +private: void create(const Field& x) { dispatch([this](auto& value) { create_concrete(value); }, x); } diff --git a/be/src/vec/data_types/convert_field_to_type.cpp b/be/src/vec/data_types/convert_field_to_type.cpp index b5c4263181eb49..af6d98cd614faa 100644 --- a/be/src/vec/data_types/convert_field_to_type.cpp +++ b/be/src/vec/data_types/convert_field_to_type.cpp @@ -32,6 +32,8 @@ #include "common/exception.h" #include "common/status.h" +#include "util/bitmap_value.h" +#include "util/jsonb_writer.h" #include "vec/common/field_visitors.h" #include "vec/common/typeid_cast.h" #include "vec/core/accurate_comparison.h" @@ -85,8 +87,76 @@ class FieldVisitorToStringSimple : public StaticVisitor { [[noreturn]] String operator()(const DecimalField& x) const { LOG(FATAL) << "not implemeted"; } + [[noreturn]] String operator()(const JsonbField& x) const { LOG(FATAL) << "not implemeted"; } }; +class FieldVisitorToJsonb : public StaticVisitor { +public: + void operator()(const Null& x, JsonbWriter* writer) const { writer->writeNull(); } + void operator()(const UInt64& x, JsonbWriter* writer) const { writer->writeInt64(x); } + void operator()(const UInt128& x, JsonbWriter* writer) const { + writer->writeInt128(int128_t(x)); + } + void operator()(const Int128& x, JsonbWriter* writer) const { + writer->writeInt128(int128_t(x)); + } + void operator()(const Int64& x, JsonbWriter* writer) const { writer->writeInt64(x); } + void operator()(const Float64& x, JsonbWriter* writer) const { writer->writeDouble(x); } + void operator()(const String& x, JsonbWriter* writer) const { + writer->writeStartString(); + writer->writeString(x); + writer->writeEndString(); + } + void operator()(const Array& x, JsonbWriter* writer) const; + + void operator()(const Tuple& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } + void operator()(const DecimalField& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } + void operator()(const DecimalField& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } + void operator()(const DecimalField& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } + void operator()(const DecimalField& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } + void operator()(const DecimalField& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } + void operator()(const doris::QuantileState& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } + void operator()(const HyperLogLog& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } + void operator()(const BitmapValue& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } + void operator()(const VariantMap& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } + void operator()(const Map& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } + void operator()(const JsonbField& x, JsonbWriter* writer) const { + throw doris::Exception(doris::ErrorCode::NOT_IMPLEMENTED_ERROR, "Not implemeted"); + } +}; + +void FieldVisitorToJsonb::operator()(const Array& x, JsonbWriter* writer) const { + const size_t size = x.size(); + writer->writeStartArray(); + for (size_t i = 0; i < size; ++i) { + Field::dispatch([writer](const auto& value) { FieldVisitorToJsonb()(value, writer); }, + x[i]); + } + writer->writeEndArray(); +} + namespace { template Field convert_numeric_type_impl(const Field& from) { @@ -175,6 +245,16 @@ void convert_field_to_typeImpl(const Field& src, const IDataType& type, // TODO this is a very simple translator, support more complex types *to = apply_visitor(FieldVisitorToStringSimple(), src); return; + } else if (which_type.is_json()) { + if (src.get_type() == Field::Types::JSONB) { + *to = src; + return; + } + JsonbWriter writer; + Field::dispatch([&writer](const auto& value) { FieldVisitorToJsonb()(value, &writer); }, + src); + *to = JsonbField(writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); + return; } else if (const DataTypeArray* type_array = typeid_cast(&type)) { if (src.get_type() == Field::Types::Array) { const Array& src_arr = src.get(); @@ -192,45 +272,6 @@ void convert_field_to_typeImpl(const Field& src, const IDataType& type, return; } } - // else if (const DataTypeTuple* type_tuple = typeid_cast(&type)) { - // if (src.get_type() == Field::Types::Tuple) { - // const auto& src_tuple = src.get(); - // size_t src_tuple_size = src_tuple.size(); - // size_t dst_tuple_size = type_tuple->get_elements().size(); - // if (dst_tuple_size != src_tuple_size) { - // return Status::InvalidArgument("Bad size of tuple in IN or VALUES section"); - // } - // Tuple res(dst_tuple_size); - // bool have_unconvertible_element = false; - // for (size_t i = 0; i < dst_tuple_size; ++i) { - // const auto& element_type = *(type_tuple->get_elements()[i]); - // RETURN_IF_ERROR(convert_field_to_type(src_tuple[i], element_type, &res[i])); - // if (!res[i].is_null() || element_type.is_nullable()) continue; - // /* - // * Either the source element was Null, or the conversion did not - // * succeed, because the source and the requested types of the - // * element are compatible, but the value is not convertible - // * (e.g. trying to convert -1 from Int8 to UInt8). In these - // * cases, consider the whole tuple also compatible but not - // * convertible. According to the specification of this function, - // * we must return Null in this case. - // * - // * The following elements might be not even compatible, so it - // * makes sense to check them to detect user errors. Remember - // * that there is an unconvertible element, and try to process - // * the remaining ones. The convert_field_to_type for each element - // * will throw if it detects incompatibility. - // */ - // have_unconvertible_element = true; - // } - // if (have_unconvertible_element) { - // return Status::InvalidArgument(fmt::format("Cannot convert {} to {}", - // src.get_type_name(), type.get_name())); - // } - // *to = Field(res); - // return Status::OK(); - // } - // } throw doris::Exception(ErrorCode::INVALID_ARGUMENT, "Type mismatch in IN or VALUES section. Expected: {}. Got: {}", type.get_name(), src.get_type()); diff --git a/be/src/vec/data_types/data_type.h b/be/src/vec/data_types/data_type.h index 08c111cc680c0a..549b32f989771e 100644 --- a/be/src/vec/data_types/data_type.h +++ b/be/src/vec/data_types/data_type.h @@ -79,6 +79,7 @@ class IDataType : private boost::noncopyable { virtual TypeDescriptor get_type_as_type_descriptor() const = 0; virtual TPrimitiveType::type get_type_as_tprimitive_type() const = 0; + virtual doris::FieldType get_storage_field_type() const = 0; virtual void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const; virtual std::string to_string(const IColumn& column, size_t row_num) const; @@ -216,10 +217,6 @@ class IDataType : private boost::noncopyable { /* the data type create from type_null, NULL literal*/ virtual bool is_null_literal() const { return false; } - /** If this data type cannot be wrapped in Nullable data type. - */ - virtual bool can_be_inside_nullable() const { return false; } - virtual bool low_cardinality() const { return false; } /// Strings, Numbers, Date, DateTime, Nullable diff --git a/be/src/vec/data_types/data_type_agg_state.h b/be/src/vec/data_types/data_type_agg_state.h index 3406c540805819..596ed792033124 100644 --- a/be/src/vec/data_types/data_type_agg_state.h +++ b/be/src/vec/data_types/data_type_agg_state.h @@ -82,6 +82,10 @@ class DataTypeAggState : public DataTypeString { return TPrimitiveType::AGG_STATE; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_AGG_STATE; + } + std::string to_string(const IColumn& column, size_t row_num) const override { std::string res = "binary("; StringRef str = column.get_data_at(row_num); diff --git a/be/src/vec/data_types/data_type_array.h b/be/src/vec/data_types/data_type_array.h index f16cb1414338b2..6335f18e12e2fd 100644 --- a/be/src/vec/data_types/data_type_array.h +++ b/be/src/vec/data_types/data_type_array.h @@ -68,12 +68,14 @@ class DataTypeArray final : public IDataType { return TPrimitiveType::ARRAY; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_ARRAY; + } + std::string do_get_name() const override { return "Array(" + nested->get_name() + ")"; } const char* get_family_name() const override { return "Array"; } - bool can_be_inside_nullable() const override { return true; } - MutableColumnPtr create_column() const override; Field get_default() const override; diff --git a/be/src/vec/data_types/data_type_bitmap.h b/be/src/vec/data_types/data_type_bitmap.h index 6fd6a7d110d277..12618c04ea890c 100644 --- a/be/src/vec/data_types/data_type_bitmap.h +++ b/be/src/vec/data_types/data_type_bitmap.h @@ -64,6 +64,10 @@ class DataTypeBitMap : public IDataType { return TPrimitiveType::OBJECT; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_OBJECT; + } + int64_t get_uncompressed_serialized_bytes(const IColumn& column, int be_exec_version) const override; char* serialize(const IColumn& column, char* buf, int be_exec_version) const override; @@ -85,8 +89,6 @@ class DataTypeBitMap : public IDataType { } bool have_maximum_size_of_value() const override { return false; } - bool can_be_inside_nullable() const override { return true; } - bool equals(const IDataType& rhs) const override { return typeid(rhs) == typeid(*this); } bool can_be_inside_low_cardinality() const override { return false; } diff --git a/be/src/vec/data_types/data_type_date.h b/be/src/vec/data_types/data_type_date.h index 8a22088cf33e1c..3db3f9396fc670 100644 --- a/be/src/vec/data_types/data_type_date.h +++ b/be/src/vec/data_types/data_type_date.h @@ -53,11 +53,13 @@ class DataTypeDate final : public DataTypeNumberBase { TPrimitiveType::type get_type_as_tprimitive_type() const override { return TPrimitiveType::DATE; } + + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_DATE; + } const char* get_family_name() const override { return "DateTime"; } std::string do_get_name() const override { return "Date"; } - bool can_be_inside_nullable() const override { return true; } - bool equals(const IDataType& rhs) const override; std::string to_string(const IColumn& column, size_t row_num) const override; void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override; diff --git a/be/src/vec/data_types/data_type_date_time.h b/be/src/vec/data_types/data_type_date_time.h index cdb87b75b61cb6..c8872e9a35ec26 100644 --- a/be/src/vec/data_types/data_type_date_time.h +++ b/be/src/vec/data_types/data_type_date_time.h @@ -80,7 +80,9 @@ class DataTypeDateTime final : public DataTypeNumberBase { return TPrimitiveType::DATETIME; } - bool can_be_inside_nullable() const override { return true; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_DATETIME; + } bool equals(const IDataType& rhs) const override; diff --git a/be/src/vec/data_types/data_type_decimal.h b/be/src/vec/data_types/data_type_decimal.h index 617b50a8752cf7..35b87afcabd331 100644 --- a/be/src/vec/data_types/data_type_decimal.h +++ b/be/src/vec/data_types/data_type_decimal.h @@ -186,6 +186,19 @@ class DataTypeDecimal final : public IDataType { __builtin_unreachable(); } + doris::FieldType get_storage_field_type() const override { + if constexpr (std::is_same_v, TypeId>) { + return doris::FieldType::OLAP_FIELD_TYPE_DECIMAL32; + } + if constexpr (std::is_same_v, TypeId>) { + return doris::FieldType::OLAP_FIELD_TYPE_DECIMAL64; + } + if constexpr (std::is_same_v, TypeId>) { + return doris::FieldType::OLAP_FIELD_TYPE_DECIMAL128I; + } + __builtin_unreachable(); + } + int64_t get_uncompressed_serialized_bytes(const IColumn& column, int be_exec_version) const override; char* serialize(const IColumn& column, char* buf, int be_exec_version) const override; @@ -237,7 +250,6 @@ class DataTypeDecimal final : public IDataType { bool is_summable() const override { return true; } bool can_be_used_in_boolean_context() const override { return true; } - bool can_be_inside_nullable() const override { return true; } std::string to_string(const IColumn& column, size_t row_num) const override; void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override; Status from_string(ReadBuffer& rb, IColumn* column) const override; diff --git a/be/src/vec/data_types/data_type_fixed_length_object.h b/be/src/vec/data_types/data_type_fixed_length_object.h index 12c27be65b122e..2b709d5dd3c521 100644 --- a/be/src/vec/data_types/data_type_fixed_length_object.h +++ b/be/src/vec/data_types/data_type_fixed_length_object.h @@ -60,6 +60,10 @@ class DataTypeFixedLengthObject final : public IDataType { return TPrimitiveType::INVALID_TYPE; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_NONE; + } + Field get_default() const override { return String(); } [[noreturn]] Field get_field(const TExprNode& node) const override { diff --git a/be/src/vec/data_types/data_type_hll.h b/be/src/vec/data_types/data_type_hll.h index 8315c749576c79..0c40868e9e4349 100644 --- a/be/src/vec/data_types/data_type_hll.h +++ b/be/src/vec/data_types/data_type_hll.h @@ -61,6 +61,10 @@ class DataTypeHLL : public IDataType { return TPrimitiveType::HLL; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_HLL; + } + int64_t get_uncompressed_serialized_bytes(const IColumn& column, int be_exec_version) const override; char* serialize(const IColumn& column, char* buf, int be_exec_version) const override; @@ -81,8 +85,6 @@ class DataTypeHLL : public IDataType { } bool have_maximum_size_of_value() const override { return false; } - bool can_be_inside_nullable() const override { return true; } - bool equals(const IDataType& rhs) const override { return typeid(rhs) == typeid(*this); } bool can_be_inside_low_cardinality() const override { return false; } diff --git a/be/src/vec/data_types/data_type_ipv4.h b/be/src/vec/data_types/data_type_ipv4.h index a8b96daaa81ae2..6270840155bc85 100644 --- a/be/src/vec/data_types/data_type_ipv4.h +++ b/be/src/vec/data_types/data_type_ipv4.h @@ -50,8 +50,6 @@ class DataTypeIPv4 final : public DataTypeNumberBase { const char* get_family_name() const override { return "IPv4"; } std::string do_get_name() const override { return "IPv4"; } - bool can_be_inside_nullable() const override { return true; } - bool equals(const IDataType& rhs) const override; std::string to_string(const IColumn& column, size_t row_num) const override; void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override; diff --git a/be/src/vec/data_types/data_type_ipv6.h b/be/src/vec/data_types/data_type_ipv6.h index abda02138c1ba4..74e2cd3d545d8f 100755 --- a/be/src/vec/data_types/data_type_ipv6.h +++ b/be/src/vec/data_types/data_type_ipv6.h @@ -51,8 +51,6 @@ class DataTypeIPv6 final : public DataTypeNumberBase { const char* get_family_name() const override { return "IPv6"; } std::string do_get_name() const override { return "IPv6"; } - bool can_be_inside_nullable() const override { return true; } - bool equals(const IDataType& rhs) const override; std::string to_string(const IColumn& column, size_t row_num) const override; void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override; diff --git a/be/src/vec/data_types/data_type_jsonb.h b/be/src/vec/data_types/data_type_jsonb.h index a00fc3b28fc78f..e6800f436e4cb9 100644 --- a/be/src/vec/data_types/data_type_jsonb.h +++ b/be/src/vec/data_types/data_type_jsonb.h @@ -60,6 +60,10 @@ class DataTypeJsonb final : public IDataType { return TPrimitiveType::JSONB; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_JSONB; + } + int64_t get_uncompressed_serialized_bytes(const IColumn& column, int data_version) const override; char* serialize(const IColumn& column, char* buf, int data_version) const override; @@ -88,7 +92,6 @@ class DataTypeJsonb final : public IDataType { bool is_value_unambiguously_represented_in_contiguous_memory_region() const override { return true; } - bool can_be_inside_nullable() const override { return true; } bool can_be_inside_low_cardinality() const override { return true; } std::string to_string(const IColumn& column, size_t row_num) const override; void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override; diff --git a/be/src/vec/data_types/data_type_map.h b/be/src/vec/data_types/data_type_map.h index d0cc89b14590f1..d5b4b61ccbd3be 100644 --- a/be/src/vec/data_types/data_type_map.h +++ b/be/src/vec/data_types/data_type_map.h @@ -68,12 +68,16 @@ class DataTypeMap final : public IDataType { TPrimitiveType::type get_type_as_tprimitive_type() const override { return TPrimitiveType::MAP; } + + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_MAP; + } + std::string do_get_name() const override { return "Map(" + key_type->get_name() + ", " + value_type->get_name() + ")"; } const char* get_family_name() const override { return "Map"; } - bool can_be_inside_nullable() const override { return true; } MutableColumnPtr create_column() const override; Field get_default() const override; diff --git a/be/src/vec/data_types/data_type_nothing.cpp b/be/src/vec/data_types/data_type_nothing.cpp index ccc201558038fe..9bae6b22e870d7 100644 --- a/be/src/vec/data_types/data_type_nothing.cpp +++ b/be/src/vec/data_types/data_type_nothing.cpp @@ -22,10 +22,12 @@ #include +#include "vec/columns/column_nothing.h" + namespace doris::vectorized { MutableColumnPtr DataTypeNothing::create_column() const { - LOG(FATAL) << "not support"; + return ColumnNothing::create(0); } char* DataTypeNothing::serialize(const IColumn& column, char* buf, int be_exec_version) const { diff --git a/be/src/vec/data_types/data_type_nothing.h b/be/src/vec/data_types/data_type_nothing.h index 16869b29b8d91c..43079f5bd29ea0 100644 --- a/be/src/vec/data_types/data_type_nothing.h +++ b/be/src/vec/data_types/data_type_nothing.h @@ -59,6 +59,10 @@ class DataTypeNothing final : public IDataType { return TPrimitiveType::INVALID_TYPE; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_NONE; + } + MutableColumnPtr create_column() const override; bool equals(const IDataType& rhs) const override; @@ -67,7 +71,6 @@ class DataTypeNothing final : public IDataType { bool text_can_contain_only_valid_utf8() const override { return true; } bool have_maximum_size_of_value() const override { return true; } size_t get_size_of_value_in_memory() const override { return 0; } - bool can_be_inside_nullable() const override { return true; } int64_t get_uncompressed_serialized_bytes(const IColumn& column, int be_exec_version) const override { diff --git a/be/src/vec/data_types/data_type_nullable.cpp b/be/src/vec/data_types/data_type_nullable.cpp index cfacd22b1edd53..d5db76ab358b7d 100644 --- a/be/src/vec/data_types/data_type_nullable.cpp +++ b/be/src/vec/data_types/data_type_nullable.cpp @@ -46,10 +46,6 @@ DataTypeNullable::DataTypeNullable(const DataTypePtr& nested_data_type_) if (!nested_data_type) { throw Exception(ErrorCode::INTERNAL_ERROR, "DataTypeNullable input nested type is nullptr"); } - if (!nested_data_type->can_be_inside_nullable()) { - throw Exception(ErrorCode::INTERNAL_ERROR, "Nested type {} cannot be inside Nullable type", - nested_data_type->get_name()); - } } bool DataTypeNullable::only_null() const { diff --git a/be/src/vec/data_types/data_type_nullable.h b/be/src/vec/data_types/data_type_nullable.h index 230931582f1f88..5d468bba67b4cd 100644 --- a/be/src/vec/data_types/data_type_nullable.h +++ b/be/src/vec/data_types/data_type_nullable.h @@ -67,6 +67,10 @@ class DataTypeNullable final : public IDataType { return nested_data_type->get_type_as_tprimitive_type(); } + doris::FieldType get_storage_field_type() const override { + return nested_data_type->get_storage_field_type(); + } + int64_t get_uncompressed_serialized_bytes(const IColumn& column, int be_exec_version) const override; char* serialize(const IColumn& column, char* buf, int be_exec_version) const override; diff --git a/be/src/vec/data_types/data_type_number.h b/be/src/vec/data_types/data_type_number.h index 09a0d1da5b4c2a..2960a0bf44a328 100644 --- a/be/src/vec/data_types/data_type_number.h +++ b/be/src/vec/data_types/data_type_number.h @@ -34,7 +34,6 @@ class DataTypeNumber final : public DataTypeNumberBase { bool is_summable() const override { return true; } bool can_be_used_in_bit_operations() const override { return true; } bool can_be_used_in_boolean_context() const override { return true; } - bool can_be_inside_nullable() const override { return true; } }; using DataTypeUInt8 = DataTypeNumber; diff --git a/be/src/vec/data_types/data_type_number_base.h b/be/src/vec/data_types/data_type_number_base.h index b55e39610ac8d4..97e3cdbf1db08e 100644 --- a/be/src/vec/data_types/data_type_number_base.h +++ b/be/src/vec/data_types/data_type_number_base.h @@ -123,6 +123,32 @@ class DataTypeNumberBase : public IDataType { LOG(FATAL) << "__builtin_unreachable"; __builtin_unreachable(); } + + doris::FieldType get_storage_field_type() const override { + if constexpr (std::is_same_v, TypeId>) { + return doris::FieldType::OLAP_FIELD_TYPE_TINYINT; + } + if constexpr (std::is_same_v, TypeId>) { + return doris::FieldType::OLAP_FIELD_TYPE_SMALLINT; + } + if constexpr (std::is_same_v, TypeId>) { + return doris::FieldType::OLAP_FIELD_TYPE_INT; + } + if constexpr (std::is_same_v, TypeId>) { + return doris::FieldType::OLAP_FIELD_TYPE_BIGINT; + } + if constexpr (std::is_same_v, TypeId>) { + return doris::FieldType::OLAP_FIELD_TYPE_LARGEINT; + } + if constexpr (std::is_same_v, TypeId>) { + return doris::FieldType::OLAP_FIELD_TYPE_FLOAT; + } + if constexpr (std::is_same_v, TypeId>) { + return doris::FieldType::OLAP_FIELD_TYPE_DOUBLE; + } + __builtin_unreachable(); + } + Field get_default() const override; Field get_field(const TExprNode& node) const override; diff --git a/be/src/vec/data_types/data_type_object.cpp b/be/src/vec/data_types/data_type_object.cpp index cd30800da66f8c..bfe071475fc822 100644 --- a/be/src/vec/data_types/data_type_object.cpp +++ b/be/src/vec/data_types/data_type_object.cpp @@ -30,6 +30,7 @@ #include #include "vec/columns/column_object.h" +#include "vec/common/assert_cast.h" #include "vec/common/typeid_cast.h" #include "vec/data_types/data_type.h" #include "vec/data_types/data_type_factory.hpp" @@ -55,7 +56,9 @@ bool DataTypeObject::equals(const IDataType& rhs) const { int64_t DataTypeObject::get_uncompressed_serialized_bytes(const IColumn& column, int be_exec_version) const { const auto& column_object = assert_cast(column); - assert(column_object.is_finalized()); + if (!column_object.is_finalized()) { + const_cast(column_object).finalize(); + } const auto& subcolumns = column_object.get_subcolumns(); size_t size = 0; @@ -81,7 +84,9 @@ int64_t DataTypeObject::get_uncompressed_serialized_bytes(const IColumn& column, char* DataTypeObject::serialize(const IColumn& column, char* buf, int be_exec_version) const { const auto& column_object = assert_cast(column); - assert(column_object.is_finalized()); + if (!column_object.is_finalized()) { + const_cast(column_object).finalize(); + } #ifndef NDEBUG // DCHECK size column_object.check_consistency(); @@ -139,8 +144,11 @@ const char* DataTypeObject::deserialize(const char* buf, IColumn* column, buf = type->deserialize(buf, sub_column.get(), be_exec_version); // add subcolumn to column_object - PathInData key {column_meta_pb.name()}; - column_object->add_sub_column(key, std::move(sub_column)); + PathInData key; + if (!column_meta_pb.name().empty()) { + key = PathInData {column_meta_pb.name()}; + } + column_object->add_sub_column(key, std::move(sub_column), type); } column_object->finalize(); @@ -151,4 +159,16 @@ const char* DataTypeObject::deserialize(const char* buf, IColumn* column, return buf; } +std::string DataTypeObject::to_string(const IColumn& column, size_t row_num) const { + const auto& variant = assert_cast(column); + std::string res; + variant.serialize_one_row_to_string(row_num, &res); + return res; +} + +void DataTypeObject::to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const { + const auto& variant = assert_cast(column); + variant.serialize_one_row_to_string(row_num, ostr); +} + } // namespace doris::vectorized diff --git a/be/src/vec/data_types/data_type_object.h b/be/src/vec/data_types/data_type_object.h index ae0514713c562b..0eb28681487594 100644 --- a/be/src/vec/data_types/data_type_object.h +++ b/be/src/vec/data_types/data_type_object.h @@ -19,6 +19,7 @@ // and modified by Doris #pragma once +#include #include #include #include @@ -51,7 +52,7 @@ class DataTypeObject : public IDataType { bool is_nullable; public: - DataTypeObject(const String& schema_format_, bool is_nullable_); + DataTypeObject(const String& schema_format_ = "json", bool is_nullable_ = true); const char* get_family_name() const override { return "Variant"; } TypeIndex get_type_id() const override { return TypeIndex::VARIANT; } TypeDescriptor get_type_as_type_descriptor() const override { @@ -60,27 +61,32 @@ class DataTypeObject : public IDataType { TPrimitiveType::type get_type_as_tprimitive_type() const override { return TPrimitiveType::VARIANT; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_VARIANT; + } MutableColumnPtr create_column() const override { return ColumnObject::create(is_nullable); } bool is_object() const override { return true; } bool equals(const IDataType& rhs) const override; bool hasNullableSubcolumns() const { return is_nullable; } bool get_is_parametric() const override { return true; } - bool can_be_inside_nullable() const override { return true; } bool have_subtypes() const override { return true; }; int64_t get_uncompressed_serialized_bytes(const IColumn& column, int be_exec_version) const override; - std::string to_string(const IColumn& column, size_t row_num) const override { - const auto& column_object = assert_cast(column); - return "Variant: " + column_object.get_keys_str(); - } + std::string to_string(const IColumn& column, size_t row_num) const override; + void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override; char* serialize(const IColumn& column, char* buf, int be_exec_version) const override; const char* deserialize(const char* buf, IColumn* column, int be_exec_version) const override; - [[noreturn]] Field get_default() const override { - LOG(FATAL) << "Method getDefault() is not implemented for data type " << get_name(); - } + Field get_default() const override { return VariantMap(); } - [[noreturn]] Field get_field(const TExprNode& node) const override { - LOG(FATAL) << "Unimplemented get_field for object"; + Field get_field(const TExprNode& node) const override { + if (node.__isset.string_literal) { + return node.string_literal.value; + } + if (node.node_type == TExprNodeType::NULL_LITERAL) { + return Field(); + } + LOG(FATAL) << "Unkown literal " << node; + return {}; } DataTypeSerDeSPtr get_serde(int nesting_level = 1) const override { diff --git a/be/src/vec/data_types/data_type_quantilestate.h b/be/src/vec/data_types/data_type_quantilestate.h index c8e25de34947d5..770b8ae7add37b 100644 --- a/be/src/vec/data_types/data_type_quantilestate.h +++ b/be/src/vec/data_types/data_type_quantilestate.h @@ -59,6 +59,9 @@ class DataTypeQuantileState : public IDataType { TPrimitiveType::type get_type_as_tprimitive_type() const override { return TPrimitiveType::QUANTILE_STATE; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_QUANTILE_STATE; + } int64_t get_uncompressed_serialized_bytes(const IColumn& column, int be_exec_version) const override; char* serialize(const IColumn& column, char* buf, int be_exec_version) const override; @@ -80,8 +83,6 @@ class DataTypeQuantileState : public IDataType { } bool have_maximum_size_of_value() const override { return false; } - bool can_be_inside_nullable() const override { return true; } - bool equals(const IDataType& rhs) const override { return typeid(rhs) == typeid(*this); } bool can_be_inside_low_cardinality() const override { return false; } diff --git a/be/src/vec/data_types/data_type_string.h b/be/src/vec/data_types/data_type_string.h index 281abd4c88adb8..6e4018bb345545 100644 --- a/be/src/vec/data_types/data_type_string.h +++ b/be/src/vec/data_types/data_type_string.h @@ -62,6 +62,9 @@ class DataTypeString : public IDataType { TPrimitiveType::type get_type_as_tprimitive_type() const override { return TPrimitiveType::STRING; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_STRING; + } int64_t get_uncompressed_serialized_bytes(const IColumn& column, int be_exec_version) const override; @@ -86,7 +89,6 @@ class DataTypeString : public IDataType { bool is_value_unambiguously_represented_in_contiguous_memory_region() const override { return true; } - bool can_be_inside_nullable() const override { return true; } bool can_be_inside_low_cardinality() const override { return true; } std::string to_string(const IColumn& column, size_t row_num) const override; void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override; diff --git a/be/src/vec/data_types/data_type_struct.h b/be/src/vec/data_types/data_type_struct.h index 550ef6caa974c5..af2dd09f36a1bb 100644 --- a/be/src/vec/data_types/data_type_struct.h +++ b/be/src/vec/data_types/data_type_struct.h @@ -85,10 +85,12 @@ class DataTypeStruct final : public IDataType { TPrimitiveType::type get_type_as_tprimitive_type() const override { return TPrimitiveType::STRUCT; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_STRUCT; + } std::string do_get_name() const override; const char* get_family_name() const override { return "Struct"; } - bool can_be_inside_nullable() const override { return true; } bool supports_sparse_serialization() const { return true; } MutableColumnPtr create_column() const override; diff --git a/be/src/vec/data_types/data_type_time.h b/be/src/vec/data_types/data_type_time.h index 323f410aa4a1b4..5f45dbb721d47e 100644 --- a/be/src/vec/data_types/data_type_time.h +++ b/be/src/vec/data_types/data_type_time.h @@ -59,6 +59,9 @@ class DataTypeTime final : public DataTypeNumberBase { TPrimitiveType::type get_type_as_tprimitive_type() const override { return TPrimitiveType::TIME; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_TIMEV2; + } void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override; @@ -67,7 +70,6 @@ class DataTypeTime final : public DataTypeNumberBase { bool is_summable() const override { return true; } bool can_be_used_in_bit_operations() const override { return true; } bool can_be_used_in_boolean_context() const override { return true; } - bool can_be_inside_nullable() const override { return true; } DataTypeSerDeSPtr get_serde(int nesting_level = 1) const override { return std::make_shared(nesting_level); @@ -103,7 +105,6 @@ class DataTypeTimeV2 final : public DataTypeNumberBase { bool is_summable() const override { return true; } bool can_be_used_in_bit_operations() const override { return true; } bool can_be_used_in_boolean_context() const override { return true; } - bool can_be_inside_nullable() const override { return true; } void to_pb_column_meta(PColumnMeta* col_meta) const override; DataTypeSerDeSPtr get_serde(int nesting_level = 1) const override { diff --git a/be/src/vec/data_types/data_type_time_v2.h b/be/src/vec/data_types/data_type_time_v2.h index e309773183ca3b..8ea0efe148152a 100644 --- a/be/src/vec/data_types/data_type_time_v2.h +++ b/be/src/vec/data_types/data_type_time_v2.h @@ -64,11 +64,12 @@ class DataTypeDateV2 final : public DataTypeNumberBase { TPrimitiveType::type get_type_as_tprimitive_type() const override { return TPrimitiveType::DATEV2; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_DATEV2; + } const char* get_family_name() const override { return "DateV2"; } std::string do_get_name() const override { return "DateV2"; } - bool can_be_inside_nullable() const override { return true; } - DataTypeSerDeSPtr get_serde(int nesting_level = 1) const override { return std::make_shared(nesting_level); } @@ -120,11 +121,12 @@ class DataTypeDateTimeV2 final : public DataTypeNumberBase { TPrimitiveType::type get_type_as_tprimitive_type() const override { return TPrimitiveType::DATETIMEV2; } + doris::FieldType get_storage_field_type() const override { + return doris::FieldType::OLAP_FIELD_TYPE_DATETIMEV2; + } const char* get_family_name() const override { return "DateTimeV2"; } std::string do_get_name() const override { return "DateTimeV2"; } - bool can_be_inside_nullable() const override { return true; } - bool equals(const IDataType& rhs) const override; std::string to_string(const IColumn& column, size_t row_num) const override; void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override; diff --git a/be/src/vec/data_types/get_least_supertype.cpp b/be/src/vec/data_types/get_least_supertype.cpp index 9db1271450d667..1baf463b052453 100644 --- a/be/src/vec/data_types/get_least_supertype.cpp +++ b/be/src/vec/data_types/get_least_supertype.cpp @@ -33,11 +33,14 @@ #include #include "common/status.h" +#include "vec/aggregate_functions/helpers.h" #include "vec/common/typeid_cast.h" #include "vec/core/types.h" #include "vec/data_types/data_type.h" +#include "vec/data_types/data_type_array.h" #include "vec/data_types/data_type_date_time.h" #include "vec/data_types/data_type_decimal.h" +#include "vec/data_types/data_type_jsonb.h" #include "vec/data_types/data_type_nothing.h" #include "vec/data_types/data_type_nullable.h" #include "vec/data_types/data_type_number.h" @@ -67,16 +70,28 @@ String get_exception_message_prefix(const DataTypes& types) { return res.str(); } +template +void throw_or_return(const DataTypes& types, int error_code, std::string_view message_suffix, + DataTypePtr* expected) { + if constexpr (on_error == LeastSupertypeOnError::String) { + *expected = std::make_shared(); + return; + } + if constexpr (on_error == LeastSupertypeOnError::Jsonb) { + *expected = std::make_shared(); + return; + } + if constexpr (on_error == LeastSupertypeOnError::Null) { + *expected = nullptr; + } + throw doris::Exception(error_code, "There is no supertype for types {} {}", + get_exception_message_prefix(types), message_suffix); +} + } // namespace -void get_numeric_type(const TypeIndexSet& types, DataTypePtr* type, bool compatible_with_string) { - auto throw_or_return = [&](std::string_view message, int error_code) { - if (compatible_with_string) { - *type = std::make_shared(); - return; - } - throw doris::Exception(error_code, message); - }; +template +void get_numeric_type(const TypeIndexSet& types, DataTypePtr* type) { bool all_numbers = true; size_t max_bits_of_signed_integer = 0; @@ -120,10 +135,7 @@ void get_numeric_type(const TypeIndexSet& types, DataTypePtr* type, bool compati max_mantissa_bits_of_floating) { if (!all_numbers) { *type = nullptr; - return throw_or_return( - get_exception_message_prefix(types) + - " because some of them are numbers and some of them are not", - doris::ErrorCode::INVALID_ARGUMENT); + return throw_or_return(types, doris::ErrorCode::INVALID_ARGUMENT, "", type); } /// If there are signed and unsigned types of same bit-width, the result must be signed number with at least one more bit. @@ -149,16 +161,16 @@ void get_numeric_type(const TypeIndexSet& types, DataTypePtr* type, bool compati *type = std::make_shared(); return; } else { - LOG(INFO) << " because some of them are integers and some are floating point " - "but there is no floating point type, that can exactly represent " - "all required integers"; + VLOG_DEBUG << " because some of them are integers and some are floating point " + "but there is no floating point type, that can exactly represent " + "all required integers"; *type = nullptr; - return throw_or_return( - get_exception_message_prefix(types) + - " because some of them are integers and some are floating point " - "but there is no floating point type, that can exactly represent " - "all required integers", - doris::ErrorCode::INVALID_ARGUMENT); + return throw_or_return( + types, doris::ErrorCode::INVALID_ARGUMENT, + " because some of them are integers and some are floating point " + "but there is no floating point type, that can exactly represent " + "all required integers", + type); } } @@ -177,14 +189,15 @@ void get_numeric_type(const TypeIndexSet& types, DataTypePtr* type, bool compati *type = std::make_shared(); return; } else { - LOG(INFO) << " because some of them are signed integers and some are unsigned " - "integers, but there is no signed integer type, that can exactly " - "represent all required unsigned integer values"; - return throw_or_return( + VLOG_DEBUG << " because some of them are signed integers and some are unsigned " + "integers, but there is no signed integer type, that can exactly " + "represent all required unsigned integer values"; + return throw_or_return( + types, doris::ErrorCode::INVALID_ARGUMENT, " because some of them are signed integers and some are unsigned " "integers, but there is no signed integer type, that can exactly " "represent all required unsigned integer values", - doris::ErrorCode::INVALID_ARGUMENT); + type); } } @@ -207,27 +220,20 @@ void get_numeric_type(const TypeIndexSet& types, DataTypePtr* type, bool compati << "but as all data types are unsigned integers, we must have found " "maximum unsigned integer type"; *type = nullptr; - return throw_or_return( - "Logical error: " + get_exception_message_prefix(types) + - " but as all data types are unsigned integers, we must have found " - "maximum unsigned integer type", - doris::ErrorCode::INVALID_ARGUMENT); + return throw_or_return( + types, doris::ErrorCode::INVALID_ARGUMENT, + " but as all data types are unsigned integers, we must have found " + "maximum unsigned integer type", + type); } } } *type = nullptr; } -// TODO conflict type resolve -void get_least_supertype(const DataTypes& types, DataTypePtr* type, bool compatible_with_string) { +template +void get_least_supertype(const DataTypes& types, DataTypePtr* type) { /// Trivial cases - auto throw_or_return = [&](std::string_view message, int error_code) { - if (compatible_with_string) { - *type = std::make_shared(); - return; - } - throw doris::Exception(error_code, String(message)); - }; if (types.empty()) { *type = std::make_shared(); return; @@ -268,7 +274,7 @@ void get_least_supertype(const DataTypes& types, DataTypePtr* type, bool compati } if (non_nothing_types.size() < types.size()) { - get_least_supertype(non_nothing_types, type, compatible_with_string); + get_least_supertype(non_nothing_types, type); return; } } @@ -295,7 +301,7 @@ void get_least_supertype(const DataTypes& types, DataTypePtr* type, bool compati if (have_nullable) { DataTypePtr nested_type; - get_least_supertype(nested_types, &nested_type, compatible_with_string); + get_least_supertype(nested_types, &nested_type); *type = std::make_shared(nested_type); return; } @@ -316,14 +322,14 @@ void get_least_supertype(const DataTypes& types, DataTypePtr* type, bool compati if (have_string || have_fixed_string) { bool all_strings = type_ids.size() == (have_string + have_fixed_string); - if (!all_strings && !compatible_with_string) { - LOG(INFO) + if (!all_strings) { + VLOG_DEBUG << get_exception_message_prefix(types) << " because some of them are String/FixedString and some of them are not"; - return throw_or_return(get_exception_message_prefix(types) + - " because some of them are String/FixedString and " - "some of them are not", - doris::ErrorCode::INVALID_ARGUMENT); + return throw_or_return(types, doris::ErrorCode::INVALID_ARGUMENT, + " because some of them are String/FixedString and " + "some of them are not", + type); } *type = std::make_shared(); @@ -339,12 +345,11 @@ void get_least_supertype(const DataTypes& types, DataTypePtr* type, bool compati if (have_date || have_datetime) { bool all_date_or_datetime = type_ids.size() == (have_date + have_datetime); if (!all_date_or_datetime) { - LOG(INFO) << get_exception_message_prefix(types) - << " because some of them are Date/DateTime and some of them are not"; - return throw_or_return( - get_exception_message_prefix(types) + - " because some of them are Date/DateTime and some of them are not", - doris::ErrorCode::INVALID_ARGUMENT); + VLOG_DEBUG << get_exception_message_prefix(types) + << " because some of them are Date/DateTime and some of them are not"; + return throw_or_return( + types, doris::ErrorCode::INVALID_ARGUMENT, + " because some of them are Date/DateTime and some of them are not", type); } *type = std::make_shared(); @@ -352,6 +357,39 @@ void get_least_supertype(const DataTypes& types, DataTypePtr* type, bool compati } } + /// For Arrays + { + bool have_array = false; + bool all_arrays = true; + DataTypes nested_types; + nested_types.reserve(types.size()); + for (const auto& type : types) { + if (const DataTypeArray* type_array = typeid_cast(type.get())) { + have_array = true; + nested_types.emplace_back(type_array->get_nested_type()); + } else { + all_arrays = false; + } + } + if (have_array) { + if (!all_arrays) { + return throw_or_return( + types, ErrorCode::INVALID_ARGUMENT, + "because some of them are Array and some of them are not", type); + } + DataTypePtr nested_type; + get_least_supertype(nested_types, &nested_type); + /// When on_error == LeastSupertypeOnError::Null and we cannot get least supertype, + /// nested_type will be nullptr, we should return nullptr in this case. + if (!nested_type) { + *type = nullptr; + return; + } + *type = std::make_shared(nested_type); + return; + } + } + /// Decimals { UInt32 have_decimal32 = type_ids.count(TypeIndex::Decimal32); @@ -379,12 +417,11 @@ void get_least_supertype(const DataTypes& types, DataTypePtr* type, bool compati } if (num_supported != type_ids.size()) { - LOG(INFO) << get_exception_message_prefix(types) - << " because some of them have no lossless convertion to Decimal"; - return throw_or_return( - get_exception_message_prefix(types) + - " because some of them have no lossless convertion to Decimal", - doris::ErrorCode::INVALID_ARGUMENT); + VLOG_DEBUG << get_exception_message_prefix(types) + << " because some of them have no lossless convertion to Decimal"; + return throw_or_return( + types, doris::ErrorCode::INVALID_ARGUMENT, + " because some of them have no lossless convertion to Decimal", type); } UInt32 max_scale = 0; @@ -404,14 +441,15 @@ void get_least_supertype(const DataTypes& types, DataTypePtr* type, bool compati } if (min_precision > DataTypeDecimal::max_precision()) { - LOG(INFO) << fmt::format("{} because the least supertype is Decimal({},{})", - get_exception_message_prefix(types), min_precision, - max_scale); - return throw_or_return(get_exception_message_prefix(types) + - fmt::format(" because some of them have no lossless " - "convertion to Decimal({},{})", - min_precision, max_scale), - doris::ErrorCode::INVALID_ARGUMENT); + VLOG_DEBUG << fmt::format("{} because the least supertype is Decimal({},{})", + get_exception_message_prefix(types), min_precision, + max_scale); + return throw_or_return( + types, doris::ErrorCode::INVALID_ARGUMENT, + fmt::format(" because some of them have no lossless " + "convertion to Decimal({},{})", + min_precision, max_scale), + type); } if (have_decimal256 || min_precision > DataTypeDecimal::max_precision()) { @@ -443,7 +481,7 @@ void get_least_supertype(const DataTypes& types, DataTypePtr* type, bool compati /// For numeric types, the most complicated part. { DataTypePtr numeric_type = nullptr; - get_numeric_type(type_ids, &numeric_type, compatible_with_string); + get_numeric_type(type_ids, &numeric_type); if (numeric_type) { *type = numeric_type; return; @@ -452,63 +490,86 @@ void get_least_supertype(const DataTypes& types, DataTypePtr* type, bool compati /// All other data types (UUID, AggregateFunction, Enum...) are compatible only if they are the same (checked in trivial cases). *type = nullptr; - return throw_or_return(get_exception_message_prefix(types), ErrorCode::INVALID_ARGUMENT); + return throw_or_return(types, ErrorCode::INVALID_ARGUMENT, "", type); } -void get_least_supertype(const TypeIndexSet& types, DataTypePtr* type, - bool compatible_with_string) { - auto throw_or_return = [&](std::string_view message, int error_code) { - if (compatible_with_string) { +template +void get_least_supertype(const TypeIndexSet& types, DataTypePtr* type) { + if (types.empty()) { + *type = std::make_shared(); + return; + } + if (types.size() == 1) { + WhichDataType which(*types.begin()); + if (which.is_nothing()) { + *type = std::make_shared(); + return; + } +#define DISPATCH(TYPE) \ + if (which.idx == TypeIndex::TYPE) { \ + *type = std::make_shared>(); \ + return; \ + } + FOR_NUMERIC_TYPES(DISPATCH) +#undef DISPATCH + if (which.is_string()) { *type = std::make_shared(); return; } - throw doris::Exception(error_code, String(message)); - }; - TypeIndexSet types_set; - for (const auto& t : types) { - if (WhichDataType(t).is_nothing()) continue; - - if (!WhichDataType(t).is_simple()) { - LOG(INFO) << "Cannot get common type by type ids with parametric type" - << getTypeName(t); - *type = nullptr; - throw doris::Exception(ErrorCode::INVALID_ARGUMENT, - "Cannot get common type by type ids with parametric type {}", - type_to_string(t)); + if (which.is_json()) { + *type = std::make_shared(); + return; } - - types_set.insert(t); + return throw_or_return( + types, ErrorCode::INVALID_ARGUMENT, + "because cannot get common type by type indexes with non-simple types", type); } - - if (types_set.empty()) { - *type = std::make_shared(); + if (types.contains(TypeIndex::String)) { + bool only_string = types.size() == 2 && types.contains(TypeIndex::Nothing); + if (!only_string) { + return throw_or_return( + types, ErrorCode::INVALID_ARGUMENT, + "because some of them are String and some of them are not", type); + } + *type = std::make_shared(); return; } - - if (types.count(TypeIndex::String)) { - if (types.size() != 1) { - LOG(INFO) << " because some of them are String and some of them are not"; - *type = nullptr; - return throw_or_return( - get_exception_message_prefix(types) + - " because some of them are String and some of them are not", - ErrorCode::INVALID_ARGUMENT); + if (types.contains(TypeIndex::JSONB)) { + bool only_json = types.size() == 2 && types.contains(TypeIndex::Nothing); + if (!only_json) { + return throw_or_return( + types, ErrorCode::INVALID_ARGUMENT, + "because some of them are Json and some of them are not", type); } - - *type = std::make_shared(); + *type = std::make_shared(); return; } /// For numeric types, the most complicated part. DataTypePtr numeric_type = nullptr; - get_numeric_type(types, &numeric_type, compatible_with_string); + get_numeric_type(types, &numeric_type); if (numeric_type) { *type = numeric_type; return; } /// All other data types (UUID, AggregateFunction, Enum...) are compatible only if they are the same (checked in trivial cases). *type = nullptr; - return throw_or_return(get_exception_message_prefix(types), ErrorCode::INVALID_ARGUMENT); + return throw_or_return(types, ErrorCode::INVALID_ARGUMENT, "", type); } +template void get_least_supertype(const DataTypes& types, + DataTypePtr* type); +template void get_least_supertype(const TypeIndexSet& types, + DataTypePtr* type); + +template void get_least_supertype(const DataTypes& types, + DataTypePtr* type); +template void get_least_supertype(const TypeIndexSet& types, + DataTypePtr* type); + +template void get_least_supertype(const DataTypes& types, + DataTypePtr* type); +template void get_least_supertype(const TypeIndexSet& types, + DataTypePtr* type); + } // namespace doris::vectorized diff --git a/be/src/vec/data_types/get_least_supertype.h b/be/src/vec/data_types/get_least_supertype.h index 72a6fc31f2c727..cee07f030b6868 100644 --- a/be/src/vec/data_types/get_least_supertype.h +++ b/be/src/vec/data_types/get_least_supertype.h @@ -40,12 +40,19 @@ namespace doris::vectorized { * Examples: there is no least common supertype for Array(UInt8), Int8. */ +enum class LeastSupertypeOnError { + Throw, + String, + Jsonb, + Null, +}; + using TypeIndexSet = phmap::flat_hash_set; -void get_least_supertype(const DataTypes& types, DataTypePtr* type, - bool compatible_with_string = false); +template +void get_least_supertype(const DataTypes& types, DataTypePtr* type); -void get_least_supertype(const TypeIndexSet& types, DataTypePtr* type, - bool compatible_with_string = false); +template +void get_least_supertype(const TypeIndexSet& types, DataTypePtr* type); } // namespace doris::vectorized diff --git a/be/src/vec/data_types/serde/data_type_array_serde.cpp b/be/src/vec/data_types/serde/data_type_array_serde.cpp index 8666f615b7fd46..91dfa8452e2778 100644 --- a/be/src/vec/data_types/serde/data_type_array_serde.cpp +++ b/be/src/vec/data_types/serde/data_type_array_serde.cpp @@ -222,6 +222,35 @@ void DataTypeArraySerDe::write_one_cell_to_jsonb(const IColumn& column, JsonbWri result.writeEndBinary(); } +void DataTypeArraySerDe::write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const { + // vectorized::Field array = column[row_num]; + // Use allocator instead of stack memory, since rapidjson hold the reference of String value + // otherwise causes stack use after free + auto& column_array = static_cast(column); + void* mem = allocator.Malloc(sizeof(vectorized::Field)); + vectorized::Field* array = new (mem) vectorized::Field(column_array[row_num]); + + convert_field_to_rapidjson(*array, result, allocator); +} + +void DataTypeArraySerDe::read_one_cell_from_json(IColumn& column, + const rapidjson::Value& result) const { + auto& column_array = static_cast(column); + auto& offsets_data = column_array.get_offsets(); + auto& nested_data = column_array.get_data(); + if (!result.IsArray()) { + column_array.insert_default(); + return; + } + // TODO this is slow should improve performance + for (const rapidjson::Value& v : result.GetArray()) { + nested_serde->read_one_cell_from_json(nested_data, v); + } + offsets_data.emplace_back(result.GetArray().Size()); +} + void DataTypeArraySerDe::read_one_cell_from_jsonb(IColumn& column, const JsonbValue* arg) const { auto blob = static_cast(arg); column.deserialize_and_insert_from_arena(blob->getBlob()); diff --git a/be/src/vec/data_types/serde/data_type_array_serde.h b/be/src/vec/data_types/serde/data_type_array_serde.h index f431f9a9f680c0..54019781f636f4 100644 --- a/be/src/vec/data_types/serde/data_type_array_serde.h +++ b/be/src/vec/data_types/serde/data_type_array_serde.h @@ -75,6 +75,11 @@ class DataTypeArraySerDe : public DataTypeSerDe { void write_one_cell_to_jsonb(const IColumn& column, JsonbWriter& result, Arena* mem_pool, int32_t col_id, int row_num) const override; + void write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const override; + void read_one_cell_from_json(IColumn& column, const rapidjson::Value& result) const override; + void read_one_cell_from_jsonb(IColumn& column, const JsonbValue* arg) const override; void write_column_to_arrow(const IColumn& column, const NullMap* null_map, diff --git a/be/src/vec/data_types/serde/data_type_jsonb_serde.cpp b/be/src/vec/data_types/serde/data_type_jsonb_serde.cpp index 6e3774fd3be88c..5e7902ed6d4785 100644 --- a/be/src/vec/data_types/serde/data_type_jsonb_serde.cpp +++ b/be/src/vec/data_types/serde/data_type_jsonb_serde.cpp @@ -17,7 +17,14 @@ #include "data_type_jsonb_serde.h" +#include +#include +#include + #include "arrow/array/builder_binary.h" +#include "common/exception.h" +#include "common/status.h" +#include "exprs/json_functions.h" #include "runtime/jsonb_value.h" namespace doris { namespace vectorized { @@ -119,5 +126,107 @@ Status DataTypeJsonbSerDe::write_column_to_orc(const std::string& timezone, cons return Status::NotSupported("write_column_to_orc with type [{}]", column.get_name()); } +static void convert_jsonb_to_rapidjson(const JsonbValue& val, rapidjson::Value& target, + rapidjson::Document::AllocatorType& allocator) { + // convert type of jsonb to rapidjson::Value + switch (val.type()) { + case JsonbType::T_True: + target.SetBool(true); + break; + case JsonbType::T_False: + target.SetBool(false); + break; + case JsonbType::T_Null: + target.SetNull(); + break; + case JsonbType::T_Float: + target.SetFloat(static_cast(val).val()); + break; + case JsonbType::T_Double: + target.SetDouble(static_cast(val).val()); + break; + case JsonbType::T_Int64: + target.SetInt64(static_cast(val).val()); + break; + case JsonbType::T_Int32: + target.SetInt(static_cast(val).val()); + break; + case JsonbType::T_Int16: + target.SetInt(static_cast(val).val()); + break; + case JsonbType::T_Int8: + target.SetInt(static_cast(val).val()); + break; + case JsonbType::T_String: + target.SetString(static_cast(val).getBlob(), + static_cast(val).getBlobLen()); + break; + case JsonbType::T_Array: { + target.SetArray(); + const ArrayVal& array = static_cast(val); + if (array.numElem() == 0) { + target.SetNull(); + break; + } + target.Reserve(array.numElem(), allocator); + for (auto it = array.begin(); it != array.end(); ++it) { + rapidjson::Value val; + convert_jsonb_to_rapidjson(*static_cast(it), val, allocator); + target.PushBack(val, allocator); + } + break; + } + case JsonbType::T_Object: { + target.SetObject(); + const ObjectVal& obj = static_cast(val); + for (auto it = obj.begin(); it != obj.end(); ++it) { + rapidjson::Value val; + convert_jsonb_to_rapidjson(*it->value(), val, allocator); + target.AddMember(rapidjson::GenericStringRef(it->getKeyStr(), it->klen()), val, + allocator); + } + break; + } + default: + CHECK(false) << "unkown type " << static_cast(val.type()); + break; + } +} + +void DataTypeJsonbSerDe::write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const { + auto& data = assert_cast(column); + const auto jsonb_val = data.get_data_at(row_num); + if (jsonb_val.empty()) { + result.SetNull(); + } + JsonbValue* val = JsonbDocument::createValue(jsonb_val.data, jsonb_val.size); + if (val == nullptr) { + throw doris::Exception(ErrorCode::INTERNAL_ERROR, "Failed to get json document from jsonb"); + } + rapidjson::Value value; + convert_jsonb_to_rapidjson(*val, value, allocator); + if (val->isObject() && result.IsObject()) { + JsonFunctions::merge_objects(result, value, allocator); + } else { + result = std::move(value); + } +} + +void DataTypeJsonbSerDe::read_one_cell_from_json(IColumn& column, + const rapidjson::Value& result) const { + // TODO improve performance + auto& col = assert_cast(column); + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + result.Accept(writer); + JsonbParser parser; + bool ok = parser.parse(buffer.GetString(), buffer.GetLength()); + CHECK(ok); + col.insert_data(parser.getWriter().getOutput()->getBuffer(), + parser.getWriter().getOutput()->getSize()); +} + } // namespace vectorized } // namespace doris diff --git a/be/src/vec/data_types/serde/data_type_jsonb_serde.h b/be/src/vec/data_types/serde/data_type_jsonb_serde.h index e2b27573103f18..b5f890b713d364 100644 --- a/be/src/vec/data_types/serde/data_type_jsonb_serde.h +++ b/be/src/vec/data_types/serde/data_type_jsonb_serde.h @@ -61,6 +61,10 @@ class DataTypeJsonbSerDe : public DataTypeStringSerDe { const NullMap* null_map, orc::ColumnVectorBatch* orc_col_batch, int start, int end, std::vector& buffer_list) const override; + void write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const override; + void read_one_cell_from_json(IColumn& column, const rapidjson::Value& result) const override; private: template diff --git a/be/src/vec/data_types/serde/data_type_nullable_serde.cpp b/be/src/vec/data_types/serde/data_type_nullable_serde.cpp index 001c52611743dd..02886b8de46142 100644 --- a/be/src/vec/data_types/serde/data_type_nullable_serde.cpp +++ b/be/src/vec/data_types/serde/data_type_nullable_serde.cpp @@ -335,5 +335,30 @@ Status DataTypeNullableSerDe::write_column_to_orc(const std::string& timezone, return Status::OK(); } +void DataTypeNullableSerDe::write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const { + auto& col = static_cast(column); + auto& nested_col = col.get_nested_column(); + if (col.is_null_at(row_num)) { + result.SetNull(); + } else { + nested_serde->write_one_cell_to_json(nested_col, result, allocator, row_num); + } +} + +void DataTypeNullableSerDe::read_one_cell_from_json(IColumn& column, + const rapidjson::Value& result) const { + auto& col = static_cast(column); + auto& nested_col = col.get_nested_column(); + if (result.IsNull()) { + col.insert_default(); + } else { + // TODO sanitize data + nested_serde->read_one_cell_from_json(nested_col, result); + col.get_null_map_column().get_data().push_back(0); + } +} + } // namespace vectorized } // namespace doris diff --git a/be/src/vec/data_types/serde/data_type_nullable_serde.h b/be/src/vec/data_types/serde/data_type_nullable_serde.h index 6b126fe860524b..19ec2ad10f59e0 100644 --- a/be/src/vec/data_types/serde/data_type_nullable_serde.h +++ b/be/src/vec/data_types/serde/data_type_nullable_serde.h @@ -89,6 +89,11 @@ class DataTypeNullableSerDe : public DataTypeSerDe { nested_serde->set_return_object_as_string(value); } + void write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const override; + void read_one_cell_from_json(IColumn& column, const rapidjson::Value& result) const override; + private: template Status _write_column_to_mysql(const IColumn& column, MysqlRowBuffer& result, diff --git a/be/src/vec/data_types/serde/data_type_number_serde.h b/be/src/vec/data_types/serde/data_type_number_serde.h index 663e714516260b..806839c1e0f425 100644 --- a/be/src/vec/data_types/serde/data_type_number_serde.h +++ b/be/src/vec/data_types/serde/data_type_number_serde.h @@ -92,6 +92,10 @@ class DataTypeNumberSerDe : public DataTypeSerDe { const NullMap* null_map, orc::ColumnVectorBatch* orc_col_batch, int start, int end, std::vector& buffer_list) const override; + void write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const override; + void read_one_cell_from_json(IColumn& column, const rapidjson::Value& result) const override; private: template @@ -284,5 +288,60 @@ void DataTypeNumberSerDe::write_one_cell_to_jsonb(const IColumn& column, } } +template +void DataTypeNumberSerDe::write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const { + const auto& data = reinterpret_cast(column).get_data(); + if constexpr (std::is_same_v || std::is_same_v || std::is_same_v) { + result.SetInt(data[row_num]); + } else if constexpr (std::is_same_v || std::is_same_v || + std::is_same_v) { + result.SetUint(data[row_num]); + } else if constexpr (std::is_same_v) { + result.SetInt64(data[row_num]); + } else if constexpr (std::is_same_v) { + result.SetUint64(data[row_num]); + } else if constexpr (std::is_same_v) { + result.SetFloat(data[row_num]); + } else if constexpr (std::is_same_v) { + result.SetDouble(data[row_num]); + } else { + LOG(FATAL) << "unknown column type " << column.get_name() << " for writing to jsonb"; + } +} + +template +void DataTypeNumberSerDe::read_one_cell_from_json(IColumn& column, + const rapidjson::Value& value) const { + auto& col = reinterpret_cast(column); + switch (value.GetType()) { + case rapidjson::Type::kNumberType: + if (value.IsUint()) { + col.insert_value((T)value.GetUint()); + } else if (value.IsInt()) { + col.insert_value((T)value.GetInt()); + } else if (value.IsUint64()) { + col.insert_value((T)value.GetUint64()); + } else if (value.IsInt64()) { + col.insert_value((T)value.GetInt64()); + } else if (value.IsFloat() || value.IsDouble()) { + col.insert_value((T)value.GetDouble()); + } else { + CHECK(false) << "Improssible"; + } + break; + case rapidjson::Type::kFalseType: + col.insert_value((T)0); + break; + case rapidjson::Type::kTrueType: + col.insert_value((T)1); + break; + default: + col.insert_default(); + break; + } +} + } // namespace vectorized } // namespace doris diff --git a/be/src/vec/data_types/serde/data_type_object_serde.cpp b/be/src/vec/data_types/serde/data_type_object_serde.cpp index 32e9b3840b7b82..94ee6a44da5c1d 100644 --- a/be/src/vec/data_types/serde/data_type_object_serde.cpp +++ b/be/src/vec/data_types/serde/data_type_object_serde.cpp @@ -17,28 +17,44 @@ #include "data_type_object_serde.h" -#include "vec/columns/column_complex.h" +#include + +#include "vec/columns/column_object.h" +#include "vec/common/assert_cast.h" +#include "vec/common/schema_util.h" + namespace doris { namespace vectorized { -Status DataTypeObjectSerDe::write_column_to_orc(const std::string& timezone, const IColumn& column, - const NullMap* null_map, - orc::ColumnVectorBatch* orc_col_batch, int start, - int end, - std::vector& buffer_list) const { - auto& col_data = assert_cast(column); - orc::StringVectorBatch* cur_batch = dynamic_cast(orc_col_batch); - - for (size_t row_id = start; row_id < end; row_id++) { - if (cur_batch->notNull[row_id] == 1) { - const auto& ele = col_data.get_data_at(row_id); - cur_batch->data[row_id] = const_cast(ele.data); - cur_batch->length[row_id] = ele.size; + +Status DataTypeObjectSerDe::write_column_to_mysql(const IColumn& column, + MysqlRowBuffer& row_buffer, int row_idx, + bool col_const) const { + const auto& variant = assert_cast(column); + if (!variant.is_finalized()) { + const_cast(variant).finalize(); + } + if (variant.is_scalar_variant()) { + // Serialize scalar types, like int, string, array, faster path + const auto& root = variant.get_subcolumn({}); + RETURN_IF_ERROR(root->get_least_common_type_serde()->write_column_to_mysql( + root->get_finalized_column(), row_buffer, row_idx, col_const)); + } else { + // Serialize hierarchy types to json format + rapidjson::StringBuffer buffer; + bool is_null = false; + if (!variant.serialize_one_row_to_json_format(row_idx, &buffer, &is_null)) { + return Status::InternalError("Invalid json format"); + } + if (is_null) { + row_buffer.push_null(); + } else { + row_buffer.push_string(buffer.GetString(), buffer.GetLength()); } } - - cur_batch->numElements = end - start; return Status::OK(); } + } // namespace vectorized + } // namespace doris \ No newline at end of file diff --git a/be/src/vec/data_types/serde/data_type_object_serde.h b/be/src/vec/data_types/serde/data_type_object_serde.h index e4c101705b0cbe..485ece2dbfe901 100644 --- a/be/src/vec/data_types/serde/data_type_object_serde.h +++ b/be/src/vec/data_types/serde/data_type_object_serde.h @@ -95,14 +95,14 @@ class DataTypeObjectSerDe : public DataTypeSerDe { } Status write_column_to_mysql(const IColumn& column, MysqlRowBuffer& row_buffer, - int row_idx, bool col_const) const override { - return Status::NotSupported("write_column_to_mysql with type " + column.get_name()); - } + int row_idx, bool col_const) const override; Status write_column_to_orc(const std::string& timezone, const IColumn& column, const NullMap* null_map, orc::ColumnVectorBatch* orc_col_batch, int start, int end, - std::vector& buffer_list) const override; + std::vector& buffer_list) const override { + return Status::NotSupported("write_column_to_orc with type " + column.get_name()); + } }; } // namespace vectorized } // namespace doris diff --git a/be/src/vec/data_types/serde/data_type_serde.cpp b/be/src/vec/data_types/serde/data_type_serde.cpp index 076eaf8f06087a..32466c47e8436c 100644 --- a/be/src/vec/data_types/serde/data_type_serde.cpp +++ b/be/src/vec/data_types/serde/data_type_serde.cpp @@ -17,6 +17,7 @@ #include "data_type_serde.h" #include "runtime/descriptors.h" +#include "vec/columns/column.h" #include "vec/data_types/data_type.h" namespace doris { @@ -41,7 +42,58 @@ DataTypeSerDeSPtrs create_data_type_serdes(const std::vector& s return serdes; } +void DataTypeSerDe::convert_array_to_rapidjson(const vectorized::Array& array, + rapidjson::Value& target, + rapidjson::Document::AllocatorType& allocator) { + for (const vectorized::Field& item : array) { + target.SetArray(); + rapidjson::Value val; + convert_field_to_rapidjson(item, val, allocator); + target.PushBack(val, allocator); + } +} + +void DataTypeSerDe::convert_field_to_rapidjson(const vectorized::Field& field, + rapidjson::Value& target, + rapidjson::Document::AllocatorType& allocator) { + switch (field.get_type()) { + case vectorized::Field::Types::Null: + target.SetNull(); + break; + case vectorized::Field::Types::Int64: + target.SetInt64(field.get()); + break; + case vectorized::Field::Types::Float64: + target.SetDouble(field.get()); + break; + case vectorized::Field::Types::String: { + const String& val = field.get(); + target.SetString(val.data(), val.size()); + break; + } + case vectorized::Field::Types::Array: { + const vectorized::Array& array = field.get(); + convert_array_to_rapidjson(array, target, allocator); + break; + } + default: + CHECK(false) << "unkown field type: " << field.get_type_name(); + break; + } +} + +void DataTypeSerDe::write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const { + LOG(FATAL) << fmt::format("Not support write {} to rapidjson", column.get_name()); +} + +void DataTypeSerDe::read_one_cell_from_json(IColumn& column, const rapidjson::Value& result) const { + LOG(FATAL) << fmt::format("Not support read {} from rapidjson", column.get_name()); +} + const std::string DataTypeSerDe::NULL_IN_COMPLEX_TYPE = "null"; const std::string DataTypeSerDe::NULL_IN_CSV_FOR_ORDINARY_TYPE = "\\N"; + } // namespace vectorized } // namespace doris diff --git a/be/src/vec/data_types/serde/data_type_serde.h b/be/src/vec/data_types/serde/data_type_serde.h index c63f07c4b2d119..917b51dabf76f2 100644 --- a/be/src/vec/data_types/serde/data_type_serde.h +++ b/be/src/vec/data_types/serde/data_type_serde.h @@ -17,6 +17,7 @@ #pragma once +#include #include #include @@ -31,6 +32,7 @@ #include "vec/common/pod_array.h" #include "vec/common/pod_array_fwd.h" #include "vec/common/string_buffer.hpp" +#include "vec/core/field.h" #include "vec/core/types.h" #include "vec/io/reader_buffer.h" @@ -273,6 +275,12 @@ class DataTypeSerDe { virtual void set_return_object_as_string(bool value) { _return_object_as_string = value; } + // rapidjson + virtual void write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const; + virtual void read_one_cell_from_json(IColumn& column, const rapidjson::Value& result) const; + protected: bool _return_object_as_string = false; // This parameter indicates what level the serde belongs to and is mainly used for complex types @@ -281,6 +289,11 @@ class DataTypeSerDe { // The _nesting_level of StructSerde is 1 // The _nesting_level of StringSerde is 2 int _nesting_level = 1; + + static void convert_field_to_rapidjson(const vectorized::Field& field, rapidjson::Value& target, + rapidjson::Document::AllocatorType& allocator); + static void convert_array_to_rapidjson(const vectorized::Array& array, rapidjson::Value& target, + rapidjson::Document::AllocatorType& allocator); }; /// Invert values since Arrow interprets 1 as a non-null value, while doris as a null diff --git a/be/src/vec/data_types/serde/data_type_string_serde.cpp b/be/src/vec/data_types/serde/data_type_string_serde.cpp index 3d4b7bfcf7b422..66d7e136592f1a 100644 --- a/be/src/vec/data_types/serde/data_type_string_serde.cpp +++ b/be/src/vec/data_types/serde/data_type_string_serde.cpp @@ -19,6 +19,9 @@ #include #include +#include +#include +#include #include #include "arrow/array/builder_binary.h" @@ -253,5 +256,26 @@ Status DataTypeStringSerDe::write_column_to_orc(const std::string& timezone, con return Status::OK(); } +void DataTypeStringSerDe::write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const { + const auto& col = static_cast(column); + const auto& data_ref = col.get_data_at(row_num); + result.SetString(data_ref.data, data_ref.size); +} + +void DataTypeStringSerDe::read_one_cell_from_json(IColumn& column, + const rapidjson::Value& result) const { + auto& col = static_cast(column); + if (!result.IsString()) { + rapidjson::StringBuffer buffer; + rapidjson::Writer writer(buffer); + result.Accept(writer); + col.insert_data(buffer.GetString(), buffer.GetSize()); + return; + } + col.insert_data(result.GetString(), result.GetStringLength()); +} + } // namespace vectorized } // namespace doris \ No newline at end of file diff --git a/be/src/vec/data_types/serde/data_type_string_serde.h b/be/src/vec/data_types/serde/data_type_string_serde.h index ba87e8029883ea..b2fbcf5a81b960 100644 --- a/be/src/vec/data_types/serde/data_type_string_serde.h +++ b/be/src/vec/data_types/serde/data_type_string_serde.h @@ -71,6 +71,10 @@ class DataTypeStringSerDe : public DataTypeSerDe { const NullMap* null_map, orc::ColumnVectorBatch* orc_col_batch, int start, int end, std::vector& buffer_list) const override; + void write_one_cell_to_json(const IColumn& column, rapidjson::Value& result, + rapidjson::Document::AllocatorType& allocator, + int row_num) const override; + void read_one_cell_from_json(IColumn& column, const rapidjson::Value& result) const override; private: template diff --git a/be/src/vec/exec/format/json/new_json_reader.cpp b/be/src/vec/exec/format/json/new_json_reader.cpp index c404bae0815e2a..1998663e244774 100644 --- a/be/src/vec/exec/format/json/new_json_reader.cpp +++ b/be/src/vec/exec/format/json/new_json_reader.cpp @@ -40,35 +40,30 @@ // IWYU pragma: no_include #include "common/compiler_util.h" // IWYU pragma: keep +#include "common/config.h" #include "common/status.h" #include "exprs/json_functions.h" #include "io/file_factory.h" #include "io/fs/buffered_reader.h" +#include "io/fs/file_reader.h" #include "io/fs/stream_load_pipe.h" +#include "runtime/define_primitive_type.h" #include "runtime/descriptors.h" #include "runtime/runtime_state.h" -#include "util/defer_op.h" -#include "vec/core/block.h" -#include "vec/exec/format/file_reader/new_plain_text_line_reader.h" -#include "vec/exec/scan/vscanner.h" -#include "vec/json/simd_json_parser.h" -// dynamic table -#include "common/config.h" -#include "io/fs/file_reader.h" -#include "runtime/define_primitive_type.h" #include "runtime/types.h" +#include "util/defer_op.h" #include "util/slice.h" #include "util/uid_util.h" #include "vec/columns/column.h" #include "vec/columns/column_nullable.h" -#include "vec/columns/column_object.h" #include "vec/columns/column_string.h" #include "vec/common/assert_cast.h" -#include "vec/common/schema_util.h" #include "vec/common/typeid_cast.h" +#include "vec/core/block.h" #include "vec/core/column_with_type_and_name.h" -#include "vec/json/json_parser.h" -#include "vec/json/parse2column.h" +#include "vec/exec/format/file_reader/new_plain_text_line_reader.h" +#include "vec/exec/scan/vscanner.h" +#include "vec/json/simd_json_parser.h" namespace doris::io { struct IOContext; diff --git a/be/src/vec/exec/format/json/new_json_reader.h b/be/src/vec/exec/format/json/new_json_reader.h index f40fe4c9f9255f..06f245840bbb48 100644 --- a/be/src/vec/exec/format/json/new_json_reader.h +++ b/be/src/vec/exec/format/json/new_json_reader.h @@ -135,7 +135,7 @@ class NewJsonReader : public GenericReader { Status _append_error_msg(const rapidjson::Value& objectValue, std::string error_msg, std::string col_name, bool* valid); - std::string _print_json_value(const rapidjson::Value& value); + static std::string _print_json_value(const rapidjson::Value& value); Status _read_one_message(std::unique_ptr* file_buf, size_t* read_size); @@ -258,7 +258,6 @@ class NewJsonReader : public GenericReader { // array_iter pointed to _array simdjson::ondemand::array_iterator _array_iter; simdjson::ondemand::array _array; - std::unique_ptr> _json_parser; std::unique_ptr _ondemand_json_parser = nullptr; // column to default value string map std::unordered_map _col_default_value_map; diff --git a/be/src/vec/functions/function.h b/be/src/vec/functions/function.h index db4ea568ffb736..a768fa1ed1349d 100644 --- a/be/src/vec/functions/function.h +++ b/be/src/vec/functions/function.h @@ -707,6 +707,7 @@ ColumnPtr wrap_in_nullable(const ColumnPtr& src, const Block& block, const Colum M(Array, ColumnArray) \ M(Map, ColumnMap) \ M(Struct, ColumnStruct) \ + M(VARIANT, ColumnObject) \ M(BitMap, ColumnBitmap) \ M(HLL, ColumnHLL) diff --git a/be/src/vec/functions/function_case.h b/be/src/vec/functions/function_case.h index 1fe306334506db..1360e47aa6a6c2 100644 --- a/be/src/vec/functions/function_case.h +++ b/be/src/vec/functions/function_case.h @@ -33,6 +33,7 @@ #include "vec/columns/column_const.h" #include "vec/columns/column_map.h" #include "vec/columns/column_nullable.h" +#include "vec/columns/column_object.h" #include "vec/columns/column_struct.h" #include "vec/columns/columns_number.h" #include "vec/core/block.h" @@ -258,6 +259,7 @@ class FunctionCase : public IFunction { std::is_same_v || std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v) { diff --git a/be/src/vec/functions/function_cast.h b/be/src/vec/functions/function_cast.h index e2bc77f0cc37ae..661e36c3472abd 100644 --- a/be/src/vec/functions/function_cast.h +++ b/be/src/vec/functions/function_cast.h @@ -22,11 +22,13 @@ #include #include +#include #include #include #include #include +#include #include #include #include @@ -53,6 +55,7 @@ #include "vec/columns/column_array.h" #include "vec/columns/column_map.h" #include "vec/columns/column_nullable.h" +#include "vec/columns/column_object.h" #include "vec/columns/column_string.h" #include "vec/columns/column_struct.h" #include "vec/columns/column_vector.h" @@ -81,6 +84,7 @@ #include "vec/data_types/data_type_map.h" #include "vec/data_types/data_type_nullable.h" #include "vec/data_types/data_type_number.h" +#include "vec/data_types/data_type_object.h" #include "vec/data_types/data_type_string.h" #include "vec/data_types/data_type_struct.h" #include "vec/data_types/data_type_time.h" @@ -641,10 +645,104 @@ struct ConvertImplNumberToJsonb { } }; +struct ConvertImplStringToJsonbAsJsonbString { + static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + const size_t result, size_t input_rows_count) { + auto data_type_to = block.get_by_position(result).type; + const auto& col_with_type_and_name = block.get_by_position(arguments[0]); + const IColumn& col_from = *col_with_type_and_name.column; + auto dst = ColumnString::create(); + ColumnString* dst_str = assert_cast(dst.get()); + const auto* from_string = assert_cast(&col_from); + JsonbWriter writer; + for (size_t i = 0; i < input_rows_count; i++) { + auto str_ref = from_string->get_data_at(i); + writer.reset(); + // write raw string to jsonb + writer.writeStartString(); + writer.writeString(str_ref.data, str_ref.size); + writer.writeEndString(); + dst_str->insert_data(writer.getOutput()->getBuffer(), writer.getOutput()->getSize()); + } + block.replace_by_position(result, std::move(dst)); + return Status::OK(); + } +}; + +struct ConvertImplGenericFromJsonb { + static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments, + const size_t result, size_t input_rows_count) { + auto data_type_to = block.get_by_position(result).type; + const auto& col_with_type_and_name = block.get_by_position(arguments[0]); + const IColumn& col_from = *col_with_type_and_name.column; + if (const ColumnString* col_from_string = check_and_get_column(&col_from)) { + auto col_to = data_type_to->create_column(); + + size_t size = col_from.size(); + col_to->reserve(size); + + ColumnUInt8::MutablePtr col_null_map_to = ColumnUInt8::create(size); + ColumnUInt8::Container* vec_null_map_to = &col_null_map_to->get_data(); + const bool is_complex = is_complex_type(data_type_to); + const bool is_dst_string = is_string_or_fixed_string(data_type_to); + for (size_t i = 0; i < size; ++i) { + const auto& val = col_from_string->get_data_at(i); + JsonbDocument* doc = JsonbDocument::createDocument(val.data, val.size); + if (UNLIKELY(!doc || !doc->getValue())) { + (*vec_null_map_to)[i] = 1; + col_to->insert_default(); + continue; + } + + // value is NOT necessary to be deleted since JsonbValue will not allocate memory + JsonbValue* value = doc->getValue(); + if (UNLIKELY(!value)) { + (*vec_null_map_to)[i] = 1; + col_to->insert_default(); + continue; + } + // Note: here we should handle the null element + if (val.size == 0) { + col_to->insert_default(); + // empty string('') is an invalid format for complex type, set null_map to 1 + if (is_complex) { + (*vec_null_map_to)[i] = 1; + } + continue; + } + // add string to string column + if (context->jsonb_string_as_string() && is_dst_string && value->isString()) { + auto blob = static_cast(value); + assert_cast(*col_to).insert_data(blob->getBlob(), + blob->getBlobLen()); + (*vec_null_map_to)[i] = 0; + continue; + } + std::string json_str = JsonbToJson::jsonb_to_json_string(val.data, val.size); + ReadBuffer read_buffer((char*)(json_str.data()), json_str.size()); + Status st = data_type_to->from_string(read_buffer, col_to); + // if parsing failed, will return null + (*vec_null_map_to)[i] = !st.ok(); + if (!st.ok()) { + col_to->insert_default(); + } + } + block.get_by_position(result).column = + ColumnNullable::create(std::move(col_to), std::move(col_null_map_to)); + } else { + return Status::RuntimeError( + "Illegal column {} of first argument of conversion function from string", + col_from.get_name()); + } + return Status::OK(); + } +}; + // Generic conversion of any type to jsonb. struct ConvertImplGenericToJsonb { static Status execute(FunctionContext* context, Block& block, const ColumnNumbers& arguments, const size_t result, size_t input_rows_count) { + auto data_type_to = block.get_by_position(result).type; const auto& col_with_type_and_name = block.get_by_position(arguments[0]); const IDataType& type = *col_with_type_and_name.type; const IColumn& col_from = *col_with_type_and_name.column; @@ -659,14 +757,19 @@ struct ConvertImplGenericToJsonb { VectorBufferWriter write_buffer(*tmp_col.get()); type.to_string(col_from, i, write_buffer); write_buffer.commit(); - // write string to jsonb writer.reset(); - writer.writeStartString(); auto str_ref = tmp_col->get_data_at(0); - writer.writeString(str_ref.data, str_ref.size); - writer.writeEndString(); - column_string->insert_data(writer.getOutput()->getBuffer(), - writer.getOutput()->getSize()); + ReadBuffer read_buffer((char*)(str_ref.data), str_ref.size); + // first try to parse string + Status st = data_type_to->from_string(read_buffer, column_string.get()); + if (!st.ok()) { + // write raw string to jsonb + writer.writeStartString(); + writer.writeString(str_ref.data, str_ref.size); + writer.writeEndString(); + column_string->insert_data(writer.getOutput()->getBuffer(), + writer.getOutput()->getSize()); + } } block.replace_by_position(result, std::move(column_string)); @@ -1844,13 +1947,8 @@ class FunctionCast final : public IFunctionBase { } // check jsonb value type and get to_type value - WrapperType create_jsonb_wrapper(const DataTypeJsonb& from_type, - const DataTypePtr& to_type) const { - // Conversion from String through parsing. - if (check_and_get_data_type(to_type.get())) { - return &ConvertImplGenericToString::execute2; - } - + WrapperType create_jsonb_wrapper(const DataTypeJsonb& from_type, const DataTypePtr& to_type, + bool jsonb_string_as_string) const { switch (to_type->get_type_id()) { case TypeIndex::UInt8: return &ConvertImplFromJsonb::execute; @@ -1866,17 +1964,22 @@ class FunctionCast final : public IFunctionBase { return &ConvertImplFromJsonb::execute; case TypeIndex::Float64: return &ConvertImplFromJsonb::execute; + case TypeIndex::String: + if (!jsonb_string_as_string) { + // Conversion from String through parsing. + return &ConvertImplGenericToString::execute2; + } else { + return ConvertImplGenericFromJsonb::execute; + } default: - return create_unsupport_wrapper(from_type.get_name(), to_type->get_name()); + return ConvertImplGenericFromJsonb::execute; } - - return nullptr; } // create cresponding jsonb value with type to_type // use jsonb writer to create jsonb value - WrapperType create_jsonb_wrapper(const DataTypePtr& from_type, - const DataTypeJsonb& to_type) const { + WrapperType create_jsonb_wrapper(const DataTypePtr& from_type, const DataTypeJsonb& to_type, + bool string_as_jsonb_string) const { switch (from_type->get_type_id()) { case TypeIndex::UInt8: return &ConvertImplNumberToJsonb::execute; @@ -1893,12 +1996,119 @@ class FunctionCast final : public IFunctionBase { case TypeIndex::Float64: return &ConvertImplNumberToJsonb::execute; case TypeIndex::String: - return &ConvertImplGenericFromString::execute; + if (string_as_jsonb_string) { + // We convert column string to jsonb type just add a string jsonb field to dst column instead of parse + // each line in original string column. + return &ConvertImplStringToJsonbAsJsonbString::execute; + } else { + return &ConvertImplGenericFromString::execute; + } default: return &ConvertImplGenericToJsonb::execute; } } + struct ConvertImplGenericFromVariant { + static Status execute(const FunctionCast* fn, FunctionContext* context, Block& block, + const ColumnNumbers& arguments, const size_t result, + size_t input_rows_count) { + auto& data_type_to = block.get_by_position(result).type; + const auto& col_with_type_and_name = block.get_by_position(arguments[0]); + auto& col_from = col_with_type_and_name.column; + auto& variant = assert_cast(*col_from); + ColumnPtr col_to = data_type_to->create_column(); + if (!variant.is_finalized()) { + variant.assume_mutable()->finalize(); + } + + if (variant.is_scalar_variant()) { + ColumnPtr nested = variant.get_root(); + auto nested_from_type = variant.get_root_type(); + DCHECK(nested_from_type->is_nullable()); + DCHECK(!data_type_to->is_nullable()); + auto new_context = context->clone(); + new_context->set_jsonb_string_as_string(true); + // dst type nullable has been removed, so we should remove the inner nullable of root column + auto wrapper = fn->prepare_impl( + new_context.get(), remove_nullable(nested_from_type), data_type_to, true); + Block tmp_block {{remove_nullable(nested), remove_nullable(nested_from_type), ""}}; + tmp_block.insert({nullptr, data_type_to, ""}); + /// Perform the requested conversion. + Status st = wrapper(new_context.get(), tmp_block, {0}, 1, input_rows_count); + if (!st.ok()) { + // Fill with default values, which is null + col_to->assume_mutable()->insert_many_defaults(input_rows_count); + col_to = make_nullable(col_to, true); + } else { + col_to = tmp_block.get_by_position(1).column; + // Note: here we should return the nullable result column + col_to = wrap_in_nullable( + col_to, + Block({{nested, nested_from_type, ""}, {col_to, data_type_to, ""}}), + {0}, 1, input_rows_count); + } + } else { + // Could not cast to any other types when it hierarchical like '{"a" : 1}' + if (!data_type_to->is_nullable() && !WhichDataType(data_type_to).is_string()) { + // TODO we should convert as many as possible here, for examle + // this variant column's root is a number column, to convert to number column + // is also acceptable + // return Status::InvalidArgument(fmt::format("Could not cast from variant to {}", + // data_type_to->get_name())); + col_to->assume_mutable()->insert_many_defaults(input_rows_count); + col_to = make_nullable(col_to, true); + } else if (WhichDataType(data_type_to).is_string()) { + return ConvertImplGenericToString::execute2(context, block, arguments, result, + input_rows_count); + } else { + assert_cast(*col_to->assume_mutable()) + .insert_many_defaults(input_rows_count); + } + } + if (col_to->size() != input_rows_count) { + return Status::InternalError("Unmatched row count {}, expected {}", col_to->size(), + input_rows_count); + } + + block.replace_by_position(result, std::move(col_to)); + return Status::OK(); + } + }; + + struct ConvertImplGenericToVariant { + static Status execute(FunctionContext* context, Block& block, + const ColumnNumbers& arguments, const size_t result, + size_t input_rows_count) { + // auto& data_type_to = block.get_by_position(result).type; + const auto& col_with_type_and_name = block.get_by_position(arguments[0]); + auto& from_type = col_with_type_and_name.type; + auto& col_from = col_with_type_and_name.column; + + // set variant root column/type to from column/type + auto variant = ColumnObject::create(true /*always nullable*/); + variant->create_root(from_type, col_from->assume_mutable()); + + block.replace_by_position(result, std::move(variant)); + return Status::OK(); + } + }; + + // create cresponding variant value to wrap from_type + WrapperType create_variant_wrapper(const DataTypePtr& from_type, + const DataTypeObject& to_type) const { + return &ConvertImplGenericToVariant::execute; + } + + // create cresponding type convert from variant + WrapperType create_variant_wrapper(const DataTypeObject& from_type, + const DataTypePtr& to_type) const { + return [this](FunctionContext* context, Block& block, const ColumnNumbers& arguments, + const size_t result, size_t input_rows_count) -> Status { + return ConvertImplGenericFromVariant::execute(this, context, block, arguments, result, + input_rows_count); + }; + } + //TODO(Amory) . Need support more cast for key , value for map WrapperType create_map_wrapper(FunctionContext* context, const DataTypePtr& from_type, const DataTypeMap& to_type) const { @@ -2048,7 +2258,11 @@ class FunctionCast final : public IFunctionBase { }; } - constexpr bool skip_not_null_check = false; + bool skip_not_null_check = false; + if (from_nested->is_nullable() && WhichDataType(to_type).is_variant_type()) { + /// Disable check for variant. Will check that column doesn't contain NULL in wrapper below. + skip_not_null_check = true; + } auto wrapper = prepare_remove_nullable(context, from_nested, to_nested, skip_not_null_check); @@ -2148,11 +2362,22 @@ class FunctionCast final : public IFunctionBase { else if (WhichDataType(from_type).is_nothing()) return create_nothing_wrapper(to_type.get()); + if (to_type->get_type_id() == TypeIndex::VARIANT) { + return create_variant_wrapper(from_type, static_cast(*to_type)); + } + if (from_type->get_type_id() == TypeIndex::VARIANT) { + return create_variant_wrapper(static_cast(*from_type), to_type); + } + if (from_type->get_type_id() == TypeIndex::JSONB) { - return create_jsonb_wrapper(static_cast(*from_type), to_type); + bool jsonb_string_as_string = context ? context->jsonb_string_as_string() : false; + return create_jsonb_wrapper(static_cast(*from_type), to_type, + jsonb_string_as_string); } if (to_type->get_type_id() == TypeIndex::JSONB) { - return create_jsonb_wrapper(from_type, static_cast(*to_type)); + bool string_as_jsonb_string = context ? context->string_as_jsonb_string() : false; + return create_jsonb_wrapper(from_type, static_cast(*to_type), + string_as_jsonb_string); } WrapperType ret; diff --git a/be/src/vec/json/json_parser.cpp b/be/src/vec/json/json_parser.cpp index a05a1737b986b8..9f89f1b8612cd8 100644 --- a/be/src/vec/json/json_parser.cpp +++ b/be/src/vec/json/json_parser.cpp @@ -27,15 +27,16 @@ #include #include +#include "common/config.h" #include "vec/json/path_in_data.h" #include "vec/json/simd_json_parser.h" namespace doris::vectorized { -template -bool JSONDataParser::extract_key(MutableColumns& columns, StringRef json, - const std::vector& keys, - const std::vector& types) { +template +bool JSONDataParser::extract_key(MutableColumns& columns, StringRef json, + const std::vector& keys, + const std::vector& types) { assert(types.size() == keys.size()); assert(columns.size() >= keys.size()); Element document; @@ -68,8 +69,9 @@ bool JSONDataParser::extract_key(MutableColumns& columns, StringRef return true; } -template -std::optional JSONDataParser::parse(const char* begin, size_t length) { +template +std::optional JSONDataParser::parse(const char* begin, + size_t length) { std::string_view json {begin, length}; Element document; if (!parser.parse(json, document)) { @@ -86,20 +88,32 @@ std::optional JSONDataParser::parse(const char* begin, return result; } -template -void JSONDataParser::traverse(const Element& element, ParseContext& ctx) { +template +void JSONDataParser::traverse(const Element& element, ParseContext& ctx) { // checkStackSize(); if (element.isObject()) { traverseObject(element.getObject(), ctx); } else if (element.isArray()) { - traverseArray(element.getArray(), ctx); + has_nested = false; + checkHasNested(element); + if (has_nested && !parse_nested && !config::enable_flatten_nested_for_variant) { + // Parse nested arrays to JsonbField + JsonbWriter writer; + traverseArrayAsJsonb(element.getArray(), writer); + ctx.paths.push_back(ctx.builder.get_parts()); + ctx.values.push_back( + JsonbField(writer.getOutput()->getBuffer(), writer.getOutput()->getSize())); + } else { + traverseArray(element.getArray(), ctx); + } } else { ctx.paths.push_back(ctx.builder.get_parts()); ctx.values.push_back(getValueAsField(element)); } } -template -void JSONDataParser::traverseObject(const JSONObject& object, ParseContext& ctx) { +template +void JSONDataParser::traverseObject(const JSONObject& object, + ParseContext& ctx) { ctx.paths.reserve(ctx.paths.size() + object.size()); ctx.values.reserve(ctx.values.size() + object.size()); for (auto it = object.begin(); it != object.end(); ++it) { @@ -109,8 +123,57 @@ void JSONDataParser::traverseObject(const JSONObject& object, ParseC ctx.builder.pop_back(); } } -template -void JSONDataParser::traverseArray(const JSONArray& array, ParseContext& ctx) { + +template +void JSONDataParser::checkHasNested(const Element& element) { + if (element.isArray()) { + const JSONArray& array = element.getArray(); + for (auto it = array.begin(); it != array.end(); ++it) { + checkHasNested(*it); + } + } + if (element.isObject()) { + has_nested = true; + } +} + +template +void JSONDataParser::traverseAsJsonb(const Element& element, + JsonbWriter& writer) { + if (element.isObject()) { + traverseObjectAsJsonb(element.getObject(), writer); + } else if (element.isArray()) { + traverseArrayAsJsonb(element.getArray(), writer); + } else { + writeValueAsJsonb(element, writer); + } +} + +template +void JSONDataParser::traverseObjectAsJsonb(const JSONObject& object, + JsonbWriter& writer) { + writer.writeStartObject(); + for (auto it = object.begin(); it != object.end(); ++it) { + const auto& [key, value] = *it; + writer.writeKey(key.data(), key.size()); + traverseAsJsonb(value, writer); + } + writer.writeEndObject(); +} + +template +void JSONDataParser::traverseArrayAsJsonb(const JSONArray& array, + JsonbWriter& writer) { + writer.writeStartArray(); + for (auto it = array.begin(); it != array.end(); ++it) { + traverseAsJsonb(*it, writer); + } + writer.writeEndArray(); +} + +template +void JSONDataParser::traverseArray(const JSONArray& array, + ParseContext& ctx) { /// Traverse elements of array and collect an array of fields by each path. ParseArrayContext array_ctx; array_ctx.total_size = array.size(); @@ -134,9 +197,9 @@ void JSONDataParser::traverseArray(const JSONArray& array, ParseCont } } } -template -void JSONDataParser::traverseArrayElement(const Element& element, - ParseArrayContext& ctx) { +template +void JSONDataParser::traverseArrayElement(const Element& element, + ParseArrayContext& ctx) { ParseContext element_ctx; traverse(element, element_ctx); auto& [_, paths, values] = element_ctx; @@ -206,8 +269,8 @@ void JSONDataParser::traverseArrayElement(const Element& element, } } -template -void JSONDataParser::fillMissedValuesInArrays(ParseArrayContext& ctx) { +template +void JSONDataParser::fillMissedValuesInArrays(ParseArrayContext& ctx) { for (auto it = ctx.arrays_by_path.begin(); it != ctx.arrays_by_path.end(); ++it) { auto& [path, path_array] = it->second; assert(path_array.size() == ctx.current_size || path_array.size() == ctx.current_size + 1); @@ -220,10 +283,9 @@ void JSONDataParser::fillMissedValuesInArrays(ParseArrayContext& ctx } } -template -bool JSONDataParser::tryInsertDefaultFromNested(ParseArrayContext& ctx, - const PathInData::Parts& path, - Array& array) { +template +bool JSONDataParser::tryInsertDefaultFromNested( + ParseArrayContext& ctx, const PathInData::Parts& path, Array& array) { /// If there is a collected size of current Nested /// then insert array of this size as a default value. if (path.empty() || array.empty()) { @@ -250,9 +312,9 @@ bool JSONDataParser::tryInsertDefaultFromNested(ParseArrayContext& c return true; } -template -StringRef JSONDataParser::getNameOfNested(const PathInData::Parts& path, - const Field& value) { +template +StringRef JSONDataParser::getNameOfNested(const PathInData::Parts& path, + const Field& value) { if (value.get_type() != Field::Types::Array || path.empty()) { return {}; } @@ -270,5 +332,6 @@ StringRef JSONDataParser::getNameOfNested(const PathInData::Parts& p return {}; } -template class JSONDataParser; +template class JSONDataParser; +template class JSONDataParser; } // namespace doris::vectorized \ No newline at end of file diff --git a/be/src/vec/json/json_parser.h b/be/src/vec/json/json_parser.h index 24d61b89b710f0..576c7dcba724cc 100644 --- a/be/src/vec/json/json_parser.h +++ b/be/src/vec/json/json_parser.h @@ -28,6 +28,7 @@ #include #include +#include "util/jsonb_writer.h" #include "vec/columns/column.h" #include "vec/common/string_ref.h" #include "vec/common/uint128.h" @@ -62,6 +63,39 @@ Field getValueAsField(const Element& element) { return Field(); } +template +void writeValueAsJsonb(const Element& element, JsonbWriter& writer) { + // bool will convert to type FiledType::UInt64 + if (element.isBool()) { + writer.writeBool(element.getBool()); + return; + } + if (element.isInt64()) { + writer.writeInt64(element.getInt64()); + return; + } + // doris only support signed integers at present + if (element.isUInt64()) { + writer.writeInt64(element.getInt64()); + return; + } + if (element.isDouble()) { + writer.writeDouble(element.getDouble()); + return; + } + if (element.isString()) { + writer.writeStartString(); + std::string_view str = element.getString(); + writer.writeString(str.data(), str.size()); + writer.writeEndString(); + return; + } + if (element.isNull()) { + writer.writeNull(); + return; + } +} + template std::string castValueAsString(const Element& element) { if (element.isBool()) { @@ -86,7 +120,7 @@ enum class ExtractType { ToString = 0, // ... }; -template +template class JSONDataParser { public: using Element = typename ParserImpl::Element; @@ -112,7 +146,6 @@ class JSONDataParser { size_t total_size = 0; PathToArray arrays_by_path; KeyToSizes nested_sizes_by_key; - // Arena strings_pool; }; void traverse(const Element& element, ParseContext& ctx); void traverseObject(const JSONObject& object, ParseContext& ctx); @@ -123,6 +156,12 @@ class JSONDataParser { Array& array); static StringRef getNameOfNested(const PathInData::Parts& path, const Field& value); + bool has_nested = false; + void checkHasNested(const Element& element); + void traverseAsJsonb(const Element& element, JsonbWriter& writer); + void traverseObjectAsJsonb(const JSONObject& object, JsonbWriter& writer); + void traverseArrayAsJsonb(const JSONArray& array, JsonbWriter& writer); + ParserImpl parser; }; diff --git a/be/src/vec/json/parse2column.cpp b/be/src/vec/json/parse2column.cpp index 134e2e934b2f0d..cc3c649bb70faa 100644 --- a/be/src/vec/json/parse2column.cpp +++ b/be/src/vec/json/parse2column.cpp @@ -97,7 +97,7 @@ class SimpleObjectPool { } }; -SimpleObjectPool> parsers_pool; +SimpleObjectPool parsers_pool; using Node = typename ColumnObject::Subcolumns::Node; /// Visitor that keeps @num_dimensions_to_keep dimensions in arrays @@ -129,68 +129,6 @@ class FieldVisitorReplaceScalars : public StaticVisitor { size_t num_dimensions_to_keep; }; -/// Finds a subcolumn from the same Nested type as @entry and inserts -/// an array with default values with consistent sizes as in Nested type. -bool try_insert_default_from_nested(const std::shared_ptr& entry, - const ColumnObject::Subcolumns& subcolumns) { - if (!entry->path.has_nested_part()) { - return false; - } - - const Node* current_node = subcolumns.find_leaf(entry->path); - const Node* leaf = nullptr; - size_t num_skipped_nested = 0; - - while (current_node) { - /// Try to find the first Nested up to the current node. - const auto* node_nested = ColumnObject::Subcolumns::find_parent( - current_node, [](const auto& candidate) { return candidate.is_nested(); }); - - if (!node_nested) { - break; - } - - /// If there are no leaves, skip current node and find - /// the next node up to the current. - leaf = ColumnObject::Subcolumns::find_leaf(node_nested, [&](const auto& candidate) { - return candidate.data.size() == entry->data.size() + 1; - }); - - if (leaf) { - break; - } - - current_node = node_nested->parent; - ++num_skipped_nested; - } - - if (!leaf) { - return false; - } - - auto last_field = leaf->data.get_last_field(); - if (last_field.is_null()) { - return false; - } - - const auto& least_common_type = entry->data.get_least_common_type(); - size_t num_dimensions = schema_util::get_number_of_dimensions(*least_common_type); - assert(num_skipped_nested < num_dimensions); - - /// Replace scalars to default values with consistent array sizes. - size_t num_dimensions_to_keep = num_dimensions - num_skipped_nested; - auto default_scalar = - num_skipped_nested - ? schema_util::create_empty_array_field(num_skipped_nested) - : schema_util::get_base_type_of_array(least_common_type)->get_default(); - - auto default_field = apply_visitor( - FieldVisitorReplaceScalars(default_scalar, num_dimensions_to_keep), last_field); - entry->data.insert(std::move(default_field)); - - return true; -} - template void parse_json_to_variant(IColumn& column, const char* src, size_t length, JSONDataParser* parser) { @@ -204,7 +142,7 @@ void parse_json_to_variant(IColumn& column, const char* src, size_t length, result = ParseResult {}; } if (!result) { - LOG(INFO) << "failed to parse " << std::string_view(src, length) << ", length= " << length; + VLOG_DEBUG << "failed to parse " << std::string_view(src, length) << ", length= " << length; throw doris::Exception(ErrorCode::INVALID_ARGUMENT, "Failed to parse object {}", std::string_view(src, length)); } @@ -215,12 +153,6 @@ void parse_json_to_variant(IColumn& column, const char* src, size_t length, for (size_t i = 0; i < paths.size(); ++i) { FieldInfo field_info; get_field_info(values[i], &field_info); - // TODO support multi dimensions array - if (!config::enable_parse_multi_dimession_array && field_info.num_dimensions >= 2) { - throw doris::Exception( - ErrorCode::INVALID_ARGUMENT, - "Sorry multi dimensions array is not supported now, we are working on it"); - } if (is_nothing(field_info.scalar_type)) { continue; } @@ -232,11 +164,7 @@ void parse_json_to_variant(IColumn& column, const char* src, size_t length, } if (!column_object.has_subcolumn(paths[i])) { - if (paths[i].has_nested_part()) { - column_object.add_nested_subcolumn(paths[i], field_info, num_rows); - } else { - column_object.add_sub_column(paths[i], num_rows); - } + column_object.add_sub_column(paths[i], num_rows); } auto* subcolumn = column_object.get_subcolumn(paths[i]); if (!subcolumn) { @@ -250,36 +178,33 @@ void parse_json_to_variant(IColumn& column, const char* src, size_t length, const auto& subcolumns = column_object.get_subcolumns(); for (const auto& entry : subcolumns) { if (!paths_set.contains(entry->path.get_path())) { - bool inserted = try_insert_default_from_nested(entry, subcolumns); - if (!inserted) { - entry->data.insertDefault(); - } + entry->data.insertDefault(); } } column_object.incr_num_rows(); } bool extract_key(MutableColumns& columns, StringRef json, const std::vector& keys, - const std::vector& types, JSONDataParser* parser) { + const std::vector& types, JsonParser* parser) { return parser->extract_key(columns, json, keys, types); } // exposed interfaces -void parse_json_to_variant(IColumn& column, const StringRef& json, - JSONDataParser* parser) { +void parse_json_to_variant(IColumn& column, const StringRef& json, JsonParser* parser) { return parse_json_to_variant(column, json.data, json.size, parser); } -void parse_json_to_variant(IColumn& column, const std::vector& jsons) { - auto parser = parsers_pool.get([] { return new JSONDataParser(); }); - for (StringRef str : jsons) { - parse_json_to_variant(column, str.data, str.size, parser.get()); +void parse_json_to_variant(IColumn& column, const ColumnString& raw_json_column) { + auto parser = parsers_pool.get([] { return new JsonParser(); }); + for (size_t i = 0; i < raw_json_column.size(); ++i) { + StringRef raw_json = raw_json_column.get_data_at(i); + parse_json_to_variant(column, raw_json.data, raw_json.size, parser.get()); } } bool extract_key(MutableColumns& columns, const std::vector& jsons, const std::vector& keys, const std::vector& types) { - auto parser = parsers_pool.get([] { return new JSONDataParser(); }); + auto parser = parsers_pool.get([] { return new JsonParser(); }); for (StringRef json : jsons) { if (!extract_key(columns, json, keys, types, parser.get())) { return false; @@ -290,7 +215,7 @@ bool extract_key(MutableColumns& columns, const std::vector& jsons, bool extract_key(MutableColumns& columns, const ColumnString& json_column, const std::vector& keys, const std::vector& types) { - auto parser = parsers_pool.get([] { return new JSONDataParser(); }); + auto parser = parsers_pool.get([] { return new JsonParser(); }); for (size_t x = 0; x < json_column.size(); ++x) { if (!extract_key(columns, json_column.get_data_at(x), keys, types, parser.get())) { return false; diff --git a/be/src/vec/json/parse2column.h b/be/src/vec/json/parse2column.h index 4e78d981642c80..9f8291d83a5a6d 100644 --- a/be/src/vec/json/parse2column.h +++ b/be/src/vec/json/parse2column.h @@ -28,19 +28,18 @@ namespace vectorized { class ColumnString; class SimdJSONParser; enum class ExtractType; -template +template class JSONDataParser; } // namespace vectorized } // namespace doris namespace doris::vectorized { - +using JsonParser = JSONDataParser; // parse a batch of json strings into column object, throws doris::Execption when failed -void parse_json_to_variant(IColumn& column, const std::vector& jsons); +void parse_json_to_variant(IColumn& column, const ColumnString& raw_json_column); // parse a single json, throws doris::Execption when failed -void parse_json_to_variant(IColumn& column, const StringRef& jsons, - JSONDataParser* parser); +void parse_json_to_variant(IColumn& column, const StringRef& jsons, JsonParser* parser); // extract keys columns from json strings into columns bool extract_key(MutableColumns& columns, const std::vector& jsons, diff --git a/be/src/vec/olap/olap_data_convertor.cpp b/be/src/vec/olap/olap_data_convertor.cpp index ef903f70a3d254..5344568e96891a 100644 --- a/be/src/vec/olap/olap_data_convertor.cpp +++ b/be/src/vec/olap/olap_data_convertor.cpp @@ -37,8 +37,12 @@ #include "vec/columns/column_decimal.h" #include "vec/columns/column_fixed_length_object.h" #include "vec/columns/column_map.h" +#include "vec/columns/column_nullable.h" +#include "vec/columns/column_object.h" +#include "vec/columns/column_string.h" #include "vec/columns/column_struct.h" #include "vec/columns/column_vector.h" +#include "vec/common/assert_cast.h" #include "vec/core/block.h" #include "vec/data_types/data_type_agg_state.h" #include "vec/data_types/data_type_array.h" @@ -166,6 +170,9 @@ OlapBlockDataConvertor::create_olap_column_data_convertor(const TabletColumn& co case FieldType::OLAP_FIELD_TYPE_DOUBLE: { return std::make_unique>(); } + case FieldType::OLAP_FIELD_TYPE_VARIANT: { + return std::make_unique(); + } case FieldType::OLAP_FIELD_TYPE_STRUCT: { std::vector sub_convertors; for (uint32_t i = 0; i < column.get_subtype_count(); i++) { @@ -595,28 +602,17 @@ const void* OlapBlockDataConvertor::OlapColumnDataConvertorVarChar::get_data_at( return null_flag ? nullptr : _slice.data() + offset; } -Status OlapBlockDataConvertor::OlapColumnDataConvertorVarChar::convert_to_olap() { - assert(_typed_column.column); - const vectorized::ColumnString* column_string = nullptr; - if (_nullmap) { - auto nullable_column = - assert_cast(_typed_column.column.get()); - column_string = assert_cast( - nullable_column->get_nested_column_ptr().get()); - } else { - column_string = assert_cast(_typed_column.column.get()); - } - +Status OlapBlockDataConvertor::OlapColumnDataConvertorVarChar::convert_to_olap( + const UInt8* null_map, const ColumnString* column_string) { assert(column_string); - const char* char_data = (const char*)(column_string->get_chars().data()); const ColumnString::Offset* offset_cur = column_string->get_offsets().data() + _row_pos; const ColumnString::Offset* offset_end = offset_cur + _num_rows; Slice* slice = _slice.data(); size_t string_offset = *(offset_cur - 1); - if (_nullmap) { - const UInt8* nullmap_cur = _nullmap + _row_pos; + if (null_map) { + const UInt8* nullmap_cur = null_map + _row_pos; while (offset_cur != offset_end) { if (!*nullmap_cur) { slice->data = const_cast(char_data + string_offset); @@ -637,7 +633,7 @@ Status OlapBlockDataConvertor::OlapColumnDataConvertorVarChar::convert_to_olap() ++slice; ++offset_cur; } - assert(nullmap_cur == _nullmap + _row_pos + _num_rows && slice == _slice.get_end_ptr()); + assert(nullmap_cur == null_map + _row_pos + _num_rows && slice == _slice.get_end_ptr()); } else { while (offset_cur != offset_end) { slice->data = const_cast(char_data + string_offset); @@ -657,6 +653,21 @@ Status OlapBlockDataConvertor::OlapColumnDataConvertorVarChar::convert_to_olap() return Status::OK(); } +Status OlapBlockDataConvertor::OlapColumnDataConvertorVarChar::convert_to_olap() { + assert(_typed_column.column); + const vectorized::ColumnString* column_string = nullptr; + if (_nullmap) { + auto nullable_column = + assert_cast(_typed_column.column.get()); + column_string = assert_cast( + nullable_column->get_nested_column_ptr().get()); + } else { + column_string = assert_cast(_typed_column.column.get()); + } + RETURN_IF_ERROR(convert_to_olap(_nullmap, column_string)); + return Status::OK(); +} + void OlapBlockDataConvertor::OlapColumnDataConvertorAggState::set_source_column( const ColumnWithTypeAndName& typed_column, size_t row_pos, size_t num_rows) { OlapBlockDataConvertor::OlapColumnDataConvertorBase::set_source_column(typed_column, row_pos, @@ -1046,4 +1057,35 @@ Status OlapBlockDataConvertor::OlapColumnDataConvertorMap::convert_to_olap( return Status::OK(); } +void OlapBlockDataConvertor::OlapColumnDataConvertorVariant::set_source_column( + const ColumnWithTypeAndName& typed_column, size_t row_pos, size_t num_rows) { + // set + auto variant = assert_cast(*typed_column.column); + if (!variant.is_finalized()) { + variant.finalize(); + } + auto root = variant.get_root(); + auto nullable = assert_cast(root.get()); + CHECK(nullable); + _root_data_column = assert_cast(&nullable->get_nested_column()); + _nullmap = nullable->get_null_map_data().data(); + _root_data_convertor->set_source_column({root->get_ptr(), nullptr, ""}, row_pos, num_rows); + OlapBlockDataConvertor::OlapColumnDataConvertorBase::set_source_column(typed_column, row_pos, + num_rows); +} + +// convert root data +Status OlapBlockDataConvertor::OlapColumnDataConvertorVariant::convert_to_olap() { + RETURN_IF_ERROR(_root_data_convertor->convert_to_olap(_nullmap, _root_data_column)); + return Status::OK(); +} + +const void* OlapBlockDataConvertor::OlapColumnDataConvertorVariant::get_data() const { + return _root_data_convertor->get_data(); +} +const void* OlapBlockDataConvertor::OlapColumnDataConvertorVariant::get_data_at( + size_t offset) const { + return _root_data_convertor->get_data_at(offset); +} + } // namespace doris::vectorized diff --git a/be/src/vec/olap/olap_data_convertor.h b/be/src/vec/olap/olap_data_convertor.h index 3f8e0d497f6b4e..0041d28ca22656 100644 --- a/be/src/vec/olap/olap_data_convertor.h +++ b/be/src/vec/olap/olap_data_convertor.h @@ -35,6 +35,7 @@ #include "runtime/collection_value.h" #include "util/slice.h" #include "vec/columns/column_nullable.h" +#include "vec/columns/column_object.h" #include "vec/columns/column_string.h" #include "vec/columns/column_vector.h" #include "vec/common/assert_cast.h" @@ -43,6 +44,7 @@ #include "vec/core/column_with_type_and_name.h" #include "vec/core/types.h" #include "vec/data_types/data_type.h" +#include "vec/data_types/data_type_object.h" namespace doris { @@ -198,6 +200,7 @@ class OlapBlockDataConvertor { size_t num_rows) override; const void* get_data() const override; const void* get_data_at(size_t offset) const override; + Status convert_to_olap(const UInt8* null_map, const ColumnString* column_array); Status convert_to_olap() override; private: @@ -480,6 +483,22 @@ class OlapBlockDataConvertor { UInt64 _base_offset; }; //OlapColumnDataConvertorMap + class OlapColumnDataConvertorVariant : public OlapColumnDataConvertorBase { + public: + OlapColumnDataConvertorVariant() + : _root_data_convertor(std::make_unique(true)) {} + void set_source_column(const ColumnWithTypeAndName& typed_column, size_t row_pos, + size_t num_rows) override; + Status convert_to_olap() override; + + const void* get_data() const override; + const void* get_data_at(size_t offset) const override; + + private: + const ColumnString* _root_data_column; + std::unique_ptr _root_data_convertor; + }; + private: std::vector _convertors; }; From fc304c0e7cd530316d4b99e0eaf39c94681350b8 Mon Sep 17 00:00:00 2001 From: xiangran0327 <40784350+xiangran0327@users.noreply.github.com> Date: Wed, 8 Nov 2023 14:46:18 +0800 Subject: [PATCH 40/88] (metric) add histogramJsonMetric and nodeInfo (#26172) Add histogramJsonMetric and nodeInfo to the interface "http://fe_host:http_port/metrics?type=json". --- .../doris/metric/JsonMetricVisitor.java | 88 ++++++++++++++++++- 1 file changed, 84 insertions(+), 4 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/metric/JsonMetricVisitor.java b/fe/fe-core/src/main/java/org/apache/doris/metric/JsonMetricVisitor.java index ffdaea30f4b7b9..81ca24094e9123 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/metric/JsonMetricVisitor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/metric/JsonMetricVisitor.java @@ -17,18 +17,22 @@ package org.apache.doris.metric; +import org.apache.doris.catalog.Env; import org.apache.doris.monitor.jvm.JvmStats; import org.apache.doris.monitor.jvm.JvmStats.GarbageCollector; import org.apache.doris.monitor.jvm.JvmStats.MemoryPool; import org.apache.doris.monitor.jvm.JvmStats.Threads; import com.codahale.metrics.Histogram; +import com.codahale.metrics.Snapshot; +import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class JsonMetricVisitor extends MetricVisitor { - private int ordinal = 0; + private int metricOrdinal = 0; + private int histogramOrdinal = 0; private boolean closed = false; // jvm @@ -113,7 +117,7 @@ private void setJvmJsonMetric(StringBuilder sb, String metric, String type, Stri @Override public void visit(String prefix, @SuppressWarnings("rawtypes") Metric metric) { - if (ordinal++ != 0) { + if (metricOrdinal++ != 0) { sb.append(",\n"); } sb.append("{\n\t\"tags\":\n\t{\n"); @@ -140,12 +144,88 @@ public void visit(String prefix, @SuppressWarnings("rawtypes") Metric metric) { @Override public void visitHistogram(String prefix, String name, Histogram histogram) { - return; + if (histogramOrdinal++ == 0) { + sb.append(",\n"); + } + + // part.part.part.k1=v1.k2=v2 + List names = new ArrayList<>(); + List tags = new ArrayList<>(); + for (String part : name.split("\\.")) { + String[] kv = part.split("="); + if (kv.length == 1) { + names.add(kv[0]); + } else if (kv.length == 2) { + tags.add(String.format("\"%s\":\"%s\"", kv[0], kv[1])); + } + } + final String fullName = prefix + String.join("_", names); + Snapshot snapshot = histogram.getSnapshot(); + setHistogramJsonMetric(sb, fullName, "\"quantile\":\"0.75\"", tags, snapshot.get75thPercentile()); + setHistogramJsonMetric(sb, fullName, "\"quantile\":\"0.95\"", tags, snapshot.get95thPercentile()); + setHistogramJsonMetric(sb, fullName, "\"quantile\":\"0.98\"", tags, snapshot.get98thPercentile()); + setHistogramJsonMetric(sb, fullName, "\"quantile\":\"0.99\"", tags, snapshot.get99thPercentile()); + setHistogramJsonMetric(sb, fullName, "\"quantile\":\"0.999\"", tags, snapshot.get999thPercentile()); + setHistogramJsonMetric(sb, fullName.concat("_sum"), null, null, + histogram.getCount() * snapshot.getMean()); + setHistogramJsonMetric(sb, fullName.concat("_count"), null, null, histogram.getCount()); + } + + private void setHistogramJsonMetric(StringBuilder sb, String metric, String quantile, + List tags, double value) { + sb.append("{\n\t\"tags\":\n\t{\n"); + sb.append("\t\t\"metric\":\"").append(metric).append("\""); + if (quantile != null) { + sb.append(",\n"); + sb.append("\t\t").append(quantile).append("\n"); + } + if (tags != null) { + for (String tag : tags) { + sb.append(",\n"); + sb.append("\t\t").append(tag).append("\n"); + } + } + sb.append("\n\t},\n"); + sb.append("\t\"unit\":\"").append("ms").append("\",\n"); + sb.append("\t\"value\":").append(value).append("\n}"); + sb.append(",\n"); } @Override public void getNodeInfo() { - return; + if (Env.getCurrentEnv().isMaster()) { + setNodeInfo(sb, "node_info", "is_master", null, 1, false); + } + setNodeInfo(sb, "node_info", "fe_node_num", "total", + Env.getCurrentEnv().getFrontends(null).size(), false); + setNodeInfo(sb, "node_info", "be_node_num", "total", + Env.getCurrentSystemInfo().getAllBackendIds(false).size(), false); + setNodeInfo(sb, "node_info", "be_node_num", "alive", + Env.getCurrentSystemInfo().getAllBackendIds(true).size(), false); + setNodeInfo(sb, "node_info", "be_node_num", "decommissioned", + Env.getCurrentSystemInfo().getDecommissionedBackendIds().size(), false); + setNodeInfo(sb, "node_info", "be_node_num", "dead", + Env.getCurrentEnv().getBrokerMgr().getAllBrokers().stream().filter(b -> !b.isAlive).count(), true); + } + + private void setNodeInfo(StringBuilder sb, String metric, String type, + String status, long value, boolean lastMetric) { + sb.append("{\n\t\"tags\":\n\t{\n"); + sb.append("\t\t\"metric\":\"").append(metric).append("\""); + if (type != null) { + sb.append(",\n"); + sb.append("\t\t\"type\":\"").append(type).append("\""); + } + if (status != null) { + sb.append(",\n"); + sb.append("\t\t\"state\":\"").append(status).append("\"\n"); + } + sb.append("\n\t},\n"); + sb.append("\t\"unit\":\"").append("nounit").append("\",\n"); + sb.append("\t\"value\":").append(value).append("\n}"); + if (!lastMetric) { + sb.append(",\n"); + } } @Override From 5d4557938af85ba8b43dd08b4505407960539d79 Mon Sep 17 00:00:00 2001 From: shuke <37901441+shuke987@users.noreply.github.com> Date: Wed, 8 Nov 2023 14:57:07 +0800 Subject: [PATCH 41/88] [regression-test](fix) fix export_struct bug (#26561) --- regression-test/suites/export/test_struct_export.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/regression-test/suites/export/test_struct_export.groovy b/regression-test/suites/export/test_struct_export.groovy index 18ef26b8341e0c..f9f2b1fc63c0f5 100644 --- a/regression-test/suites/export/test_struct_export.groovy +++ b/regression-test/suites/export/test_struct_export.groovy @@ -86,6 +86,7 @@ suite("test_struct_export", "export") { if (backends.size() > 1) { outFile = "/tmp" } + def url = "" def urlHost = "" def csvFiles = "" logger.info("test_struct_export the outFilePath=" + outFilePath) From f80495da8374a73409cbf61f3ca2fe371b89fc30 Mon Sep 17 00:00:00 2001 From: morrySnow <101034200+morrySnow@users.noreply.github.com> Date: Wed, 8 Nov 2023 15:16:50 +0800 Subject: [PATCH 42/88] [fix](Nereids) ban right outer, right anti, full outer with bucket shuffle (#26529) if left bucket has no data, we do not generate left bucket instance. These join should reserve all right side data. But because left instance is not exists. So right data will be discard since no dest be set. We ban these join temporarily until we could generate all instance for left side in Coordinator. --- .../ChildrenPropertiesRegulator.java | 27 +++++++++++++++---- .../shape/query72.out | 5 ++-- .../shape/query72.out | 5 ++-- .../shape/query80.out | 3 ++- .../nereids_p0/join/test_outer_join.groovy | 26 ++++++++++++++++++ 5 files changed, 56 insertions(+), 10 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildrenPropertiesRegulator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildrenPropertiesRegulator.java index 1174602da773d8..f0a2331105fa8d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildrenPropertiesRegulator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildrenPropertiesRegulator.java @@ -30,6 +30,7 @@ import org.apache.doris.nereids.trees.expressions.SlotReference; import org.apache.doris.nereids.trees.expressions.functions.agg.MultiDistinction; import org.apache.doris.nereids.trees.plans.AggMode; +import org.apache.doris.nereids.trees.plans.JoinType; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.SortPhase; import org.apache.doris.nereids.trees.plans.physical.AbstractPhysicalSort; @@ -178,6 +179,12 @@ public Boolean visitPhysicalFilter(PhysicalFilter filter, Void c return true; } + private boolean couldNotRightBucketShuffleJoin(JoinType joinType) { + return joinType == JoinType.RIGHT_ANTI_JOIN + || joinType == JoinType.RIGHT_OUTER_JOIN + || joinType == JoinType.FULL_OUTER_JOIN; + } + @Override public Boolean visitPhysicalHashJoin(PhysicalHashJoin hashJoin, Void context) { @@ -207,12 +214,22 @@ public Boolean visitPhysicalHashJoin(PhysicalHashJoin updatedForLeft = Optional.empty(); Optional updatedForRight = Optional.empty(); - if ((leftHashSpec.getShuffleType() == ShuffleType.NATURAL - && rightHashSpec.getShuffleType() == ShuffleType.NATURAL)) { + if (JoinUtils.couldColocateJoin(leftHashSpec, rightHashSpec)) { // check colocate join with scan - if (JoinUtils.couldColocateJoin(leftHashSpec, rightHashSpec)) { - return true; - } + return true; + } else if (couldNotRightBucketShuffleJoin(hashJoin.getJoinType())) { + // right anti, right outer, full outer join could not do bucket shuffle join + // TODO remove this after we refactor coordinator + updatedForLeft = Optional.of(calAnotherSideRequired( + ShuffleType.EXECUTION_BUCKETED, leftHashSpec, leftHashSpec, + (DistributionSpecHash) requiredProperties.get(0).getDistributionSpec(), + (DistributionSpecHash) requiredProperties.get(0).getDistributionSpec())); + updatedForRight = Optional.of(calAnotherSideRequired( + ShuffleType.EXECUTION_BUCKETED, leftHashSpec, rightHashSpec, + (DistributionSpecHash) requiredProperties.get(0).getDistributionSpec(), + (DistributionSpecHash) requiredProperties.get(1).getDistributionSpec())); + } else if ((leftHashSpec.getShuffleType() == ShuffleType.NATURAL + && rightHashSpec.getShuffleType() == ShuffleType.NATURAL)) { updatedForRight = Optional.of(calAnotherSideRequired( ShuffleType.STORAGE_BUCKETED, leftHashSpec, rightHashSpec, (DistributionSpecHash) requiredProperties.get(0).getDistributionSpec(), diff --git a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query72.out b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query72.out index 5d955223c399ba..ffbb06a508a591 100644 --- a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query72.out +++ b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query72.out @@ -17,8 +17,9 @@ PhysicalResultSink ------------------------PhysicalProject --------------------------hashJoin[INNER_JOIN] hashCondition=((d1.d_week_seq = d2.d_week_seq))otherCondition=() ----------------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((catalog_returns.cr_item_sk = catalog_sales.cs_item_sk) and (catalog_returns.cr_order_number = catalog_sales.cs_order_number))otherCondition=() -------------------------------PhysicalProject ---------------------------------PhysicalOlapScan[catalog_returns] +------------------------------PhysicalDistribute +--------------------------------PhysicalProject +----------------------------------PhysicalOlapScan[catalog_returns] ------------------------------PhysicalDistribute --------------------------------PhysicalProject ----------------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = catalog_sales.cs_item_sk))otherCondition=() diff --git a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query72.out b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query72.out index 4f5be2c3f7e3fb..ead7385767361c 100644 --- a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query72.out +++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query72.out @@ -18,8 +18,9 @@ PhysicalResultSink --------------------------hashJoin[INNER_JOIN] hashCondition=((d1.d_week_seq = d2.d_week_seq))otherCondition=() ----------------------------PhysicalDistribute ------------------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((catalog_returns.cr_item_sk = catalog_sales.cs_item_sk) and (catalog_returns.cr_order_number = catalog_sales.cs_order_number))otherCondition=() ---------------------------------PhysicalProject -----------------------------------PhysicalOlapScan[catalog_returns] +--------------------------------PhysicalDistribute +----------------------------------PhysicalProject +------------------------------------PhysicalOlapScan[catalog_returns] --------------------------------PhysicalDistribute ----------------------------------PhysicalProject ------------------------------------hashJoin[LEFT_OUTER_JOIN] hashCondition=((catalog_sales.cs_promo_sk = promotion.p_promo_sk))otherCondition=() diff --git a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query80.out b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query80.out index f25f72e178651e..1c24205ee4d665 100644 --- a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query80.out +++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query80.out @@ -62,7 +62,8 @@ PhysicalResultSink --------------------------hashAgg[LOCAL] ----------------------------PhysicalProject ------------------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((web_sales.ws_item_sk = web_returns.wr_item_sk) and (web_sales.ws_order_number = web_returns.wr_order_number))otherCondition=() ---------------------------------PhysicalOlapScan[web_returns] +--------------------------------PhysicalDistribute +----------------------------------PhysicalOlapScan[web_returns] --------------------------------PhysicalDistribute ----------------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_web_site_sk = web_site.web_site_sk))otherCondition=() ------------------------------------hashJoin[INNER_JOIN] hashCondition=((web_sales.ws_item_sk = item.i_item_sk))otherCondition=() diff --git a/regression-test/suites/nereids_p0/join/test_outer_join.groovy b/regression-test/suites/nereids_p0/join/test_outer_join.groovy index 3dc132d08efd05..562326175e9af4 100644 --- a/regression-test/suites/nereids_p0/join/test_outer_join.groovy +++ b/regression-test/suites/nereids_p0/join/test_outer_join.groovy @@ -20,6 +20,7 @@ suite("test_outer_join", "nereids_p0") { sql "SET enable_fallback_to_original_planner=false" def tbl1 = "test_outer_join1" def tbl2 = "test_outer_join2" + def tbl3 = "test_outer_join3" sql "DROP TABLE IF EXISTS ${tbl1}" sql """ @@ -37,6 +38,15 @@ suite("test_outer_join", "nereids_p0") { DISTRIBUTED BY RANDOM BUCKETS 30 PROPERTIES ("replication_num" = "1"); """ + + sql "DROP TABLE IF EXISTS ${tbl3}" + sql """ + CREATE TABLE IF NOT EXISTS ${tbl3} ( + c0 DECIMALV3(8,3) + ) + DISTRIBUTED BY HASH (c0) BUCKETS 1 PROPERTIES ("replication_num" = "1"); + """ + sql """INSERT INTO ${tbl2} (c0) VALUES ('dr'), ('x7Tq'), ('');""" sql """INSERT INTO ${tbl1} (c0) VALUES (0.47683432698249817), (0.8864791393280029);""" sql """INSERT INTO ${tbl1} (c0) VALUES (0.11287713050842285);""" @@ -56,6 +66,22 @@ suite("test_outer_join", "nereids_p0") { qt_join """ SELECT * FROM ${tbl2} LEFT OUTER JOIN ${tbl1} ON (('') like ('15DScmSM')) WHERE ('abc' NOT LIKE 'abc'); """ + + sql "set disable_join_reorder=true" + explain { + sql "SELECT * FROM ${tbl1} RIGHT OUTER JOIN ${tbl3} ON ${tbl1}.c0 = ${tbl3}.c0" + contains "RIGHT OUTER JOIN(PARTITIONED)" + } + explain { + sql "SELECT * FROM ${tbl1} RIGHT ANTI JOIN ${tbl3} ON ${tbl1}.c0 = ${tbl3}.c0" + contains "RIGHT ANTI JOIN(PARTITIONED)" + } + explain { + sql "SELECT * FROM ${tbl1} FULL OUTER JOIN ${tbl3} ON ${tbl1}.c0 = ${tbl3}.c0" + contains "FULL OUTER JOIN(PARTITIONED)" + } + sql "DROP TABLE IF EXISTS ${tbl1}" sql "DROP TABLE IF EXISTS ${tbl2}" + sql "DROP TABLE IF EXISTS ${tbl3}" } From be7d49cb9f4f3da7860e90662b113f9dd4f83411 Mon Sep 17 00:00:00 2001 From: xy Date: Wed, 8 Nov 2023 15:19:34 +0800 Subject: [PATCH 43/88] [Fix](doc) Fixed some errors in the documentation (#26410) Co-authored-by: xingying01 --- docs/en/docs/data-operate/update-delete/batch-delete-manual.md | 2 +- .../docs/admin-manual/maint-monitor/monitor-metrics/metrics.md | 2 +- .../docs/data-operate/update-delete/batch-delete-manual.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/docs/data-operate/update-delete/batch-delete-manual.md b/docs/en/docs/data-operate/update-delete/batch-delete-manual.md index 32f36b3bafbf6d..d4debb04808d5f 100644 --- a/docs/en/docs/data-operate/update-delete/batch-delete-manual.md +++ b/docs/en/docs/data-operate/update-delete/batch-delete-manual.md @@ -58,7 +58,7 @@ In Base Compaction, delete the rows marked for deletion to reduce the space occu There are two ways of enabling batch delete support: -1. By adding `enable_batch_delete_by_default=true` in the fe configuration file, all newly created tables after restarting fe support batch deletion, this option defaults to false +1. By adding `enable_batch_delete_by_default=true` in the fe configuration file, all newly created tables after restarting fe support batch deletion, this option defaults to true 2. For tables that have not changed the above fe configuration or for existing tables that do not support the bulk delete function, you can use the following statement: `ALTER TABLE tablename ENABLE FEATURE "BATCH_DELETE"` to enable the batch delete. diff --git a/docs/zh-CN/docs/admin-manual/maint-monitor/monitor-metrics/metrics.md b/docs/zh-CN/docs/admin-manual/maint-monitor/monitor-metrics/metrics.md index 1f6e28987701b8..129bfdb069edcc 100644 --- a/docs/zh-CN/docs/admin-manual/maint-monitor/monitor-metrics/metrics.md +++ b/docs/zh-CN/docs/admin-manual/maint-monitor/monitor-metrics/metrics.md @@ -196,7 +196,7 @@ curl http://be_host:webserver_port/metrics?type=json |`doris_be_cache_lookup_count`| | | 记录指定 LRU Cache 被查找的次数 | | |`doris_be_cache_hit_count`| | | 记录指定 LRU Cache 的命中次数 | | |`doris_be_cache_hit_ratio`| | | 记录指定 LRU Cache 的命中率 | 用于观测cache是否有效 | P0| -|| {name="DataPageCache"} | 字节 | DataPageCache 用于缓存数据的 Data Page | 数据Cache,直接影响查询效率 | P0| +|| {name="DataPageCache"} | Num | DataPageCache 用于缓存数据的 Data Page | 数据Cache,直接影响查询效率 | P0| || {name="IndexPageCache"} | Num| IndexPageCache 用于缓存数据的 Index Page | 索引Cache,直接影响查询效率 | P0| || {name="LastestSuccessChannelCache"} | Num| LastestSuccessChannelCache 用于缓存导入接收端的 LoadChannel | | || {name="SegmentCache"} | Num | SegmentCache 用于缓存已打开的 Segment,如索引信息 | | diff --git a/docs/zh-CN/docs/data-operate/update-delete/batch-delete-manual.md b/docs/zh-CN/docs/data-operate/update-delete/batch-delete-manual.md index d9df36a805e49c..62a5e869bfab18 100644 --- a/docs/zh-CN/docs/data-operate/update-delete/batch-delete-manual.md +++ b/docs/zh-CN/docs/data-operate/update-delete/batch-delete-manual.md @@ -60,7 +60,7 @@ Base Compaction 时要将标记为删除的行的删掉,以减少数据占用 启用批量删除支持有一下两种形式: -1. 通过在fe 配置文件中增加`enable_batch_delete_by_default=true` 重启fe 后新建表的都支持批量删除,此选项默认为false; +1. 通过在fe 配置文件中增加`enable_batch_delete_by_default=true` 重启fe 后新建表的都支持批量删除,此选项默认为true; 2. 对于没有更改上述fe配置或对于已存在的不支持批量删除功能的表,可以使用如下语句: `ALTER TABLE tablename ENABLE FEATURE "BATCH_DELETE"` 来启用批量删除。本操作本质上是一个schema change 操作,操作立即返回,可以通过`show alter table column` 来确认操作是否完成。 那么如何确定一个表是否支持批量删除,可以通过设置一个session variable 来显示隐藏列 `SET show_hidden_columns=true` ,之后使用`desc tablename`,如果输出中有`__DORIS_DELETE_SIGN__` 列则支持,如果没有则不支持。 From a3666aa87eb47d0428283b016d8a371a94f65e11 Mon Sep 17 00:00:00 2001 From: TengJianPing <18241664+jacktengg@users.noreply.github.com> Date: Wed, 8 Nov 2023 15:21:01 +0800 Subject: [PATCH 44/88] [feature](decimal) support decimal256 when creating table (#26308) --- be/src/exec/olap_common.h | 2 +- be/src/gutil/endian.h | 3 +- be/src/olap/types.h | 13 +- be/src/runtime/type_limit.h | 4 +- be/src/util/string_parser.hpp | 4 +- be/src/vec/common/int_exp.h | 48 +- be/src/vec/core/accurate_comparison.h | 12 +- be/src/vec/core/decimal_comparison.h | 2 +- be/src/vec/core/decomposed_float.h | 11 +- be/src/vec/core/extended_types.h | 66 +- be/src/vec/core/field.h | 2 +- be/src/vec/core/types.h | 48 +- be/src/vec/data_types/data_type_decimal.h | 2 +- .../org/apache/doris/catalog/ArrayType.java | 10 +- .../org/apache/doris/catalog/MapType.java | 14 +- .../org/apache/doris/catalog/ScalarType.java | 12 +- .../org/apache/doris/catalog/StructType.java | 9 +- .../apache/doris/catalog/TemplateType.java | 4 +- .../java/org/apache/doris/catalog/Type.java | 29 +- .../apache/doris/analysis/AnalyticExpr.java | 4 +- .../org/apache/doris/analysis/Analyzer.java | 9 +- .../apache/doris/analysis/ArithmeticExpr.java | 11 +- .../apache/doris/analysis/ArrayLiteral.java | 2 +- .../doris/analysis/BinaryPredicate.java | 7 +- .../apache/doris/analysis/DateLiteral.java | 3 +- .../apache/doris/analysis/DecimalLiteral.java | 1 + .../java/org/apache/doris/analysis/Expr.java | 3 +- .../doris/analysis/FunctionCallExpr.java | 19 +- .../doris/analysis/LargeIntLiteral.java | 16 +- .../org/apache/doris/analysis/MapLiteral.java | 6 +- .../org/apache/doris/analysis/TypeDef.java | 11 +- .../org/apache/doris/catalog/Function.java | 7 +- .../org/apache/doris/catalog/FunctionSet.java | 7 +- .../apache/doris/catalog/PartitionKey.java | 5 +- .../nereids/trees/expressions/Multiply.java | 2 +- .../functions/ComputePrecisionForSum.java | 2 +- .../ImplicitlyCastableSignature.java | 4 +- .../trees/expressions/functions/agg/Avg.java | 2 +- .../plans/logical/LogicalSetOperation.java | 4 +- .../doris/nereids/types/DecimalV3Type.java | 8 +- .../org/apache/doris/qe/SessionVariable.java | 11 +- .../doris/statistics/util/StatisticsUtil.java | 2 + .../rules/analysis/GenerateFunction.java | 2 +- .../decimalv3/test_arithmetic_expressions.out | 177 + .../decimalv3/test_decimal256_cast.out | 25 + .../decimalv3/test_decimal256_index.out | 259 ++ .../decimalv3/test_decimal256_load.csv | 19 + .../decimalv3/test_decimal256_load.out | 664 +++ .../decimalv3/test_decimal256_outfile_csv.out | 22 + .../decimalv3/test_decimal256_predicate.out | 178 + .../test_decimal256_zonemap_index.csv | 4096 +++++++++++++++++ .../datatype_p0/decimalv3/test_predicate.out | 34 + .../test_arithmetic_expressions.groovy | 37 +- .../decimalv3/test_decimal256_cast.groovy | 40 + .../decimalv3/test_decimal256_index.groovy | 277 ++ .../decimalv3/test_decimal256_load.groovy | 345 ++ .../test_decimal256_outfile_csv.groovy | 135 + .../test_decimal256_predicate.groovy | 128 + .../decimalv3/test_predicate.groovy | 46 +- 59 files changed, 6667 insertions(+), 258 deletions(-) create mode 100644 regression-test/data/datatype_p0/decimalv3/test_decimal256_cast.out create mode 100644 regression-test/data/datatype_p0/decimalv3/test_decimal256_index.out create mode 100644 regression-test/data/datatype_p0/decimalv3/test_decimal256_load.csv create mode 100644 regression-test/data/datatype_p0/decimalv3/test_decimal256_load.out create mode 100644 regression-test/data/datatype_p0/decimalv3/test_decimal256_outfile_csv.out create mode 100644 regression-test/data/datatype_p0/decimalv3/test_decimal256_predicate.out create mode 100644 regression-test/data/datatype_p0/decimalv3/test_decimal256_zonemap_index.csv create mode 100644 regression-test/suites/datatype_p0/decimalv3/test_decimal256_cast.groovy create mode 100644 regression-test/suites/datatype_p0/decimalv3/test_decimal256_index.groovy create mode 100644 regression-test/suites/datatype_p0/decimalv3/test_decimal256_load.groovy create mode 100644 regression-test/suites/datatype_p0/decimalv3/test_decimal256_outfile_csv.groovy create mode 100644 regression-test/suites/datatype_p0/decimalv3/test_decimal256_predicate.groovy diff --git a/be/src/exec/olap_common.h b/be/src/exec/olap_common.h index 47005ef042faad..91a27d980f826d 100644 --- a/be/src/exec/olap_common.h +++ b/be/src/exec/olap_common.h @@ -55,7 +55,7 @@ std::string cast_to_string(T value, int scale) { } else if constexpr (primitive_type == TYPE_DECIMAL128I) { return ((vectorized::Decimal)value).to_string(scale); } else if constexpr (primitive_type == TYPE_DECIMAL256) { - return ((vectorized::Decimal)value).to_string(scale); + return ((vectorized::Decimal)value).to_string(scale); } else if constexpr (primitive_type == TYPE_TINYINT) { return std::to_string(static_cast(value)); } else if constexpr (primitive_type == TYPE_LARGEINT) { diff --git a/be/src/gutil/endian.h b/be/src/gutil/endian.h index 66d849f73cd554..f1a9cf2a1a2da1 100644 --- a/be/src/gutil/endian.h +++ b/be/src/gutil/endian.h @@ -61,7 +61,8 @@ inline unsigned __int128 gbswap_128(unsigned __int128 host_int) { } inline wide::UInt256 gbswap_256(wide::UInt256 host_int) { - wide::UInt256 result{gbswap_64(host_int.items[0]), gbswap_64(host_int.items[1]), gbswap_64(host_int.items[2]), gbswap_64(host_int.items[3])}; + wide::UInt256 result{gbswap_64(host_int.items[3]), gbswap_64(host_int.items[2]), + gbswap_64(host_int.items[1]), gbswap_64(host_int.items[0])}; return result; } diff --git a/be/src/olap/types.h b/be/src/olap/types.h index 40c68a3e369e3c..a0c38975f72978 100644 --- a/be/src/olap/types.h +++ b/be/src/olap/types.h @@ -693,7 +693,7 @@ struct CppTypeTraits { }; template <> struct CppTypeTraits { - using CppType = Int256; + using CppType = wide::Int256; using UnsignedCppType = wide::UInt256; }; template <> @@ -1210,17 +1210,12 @@ struct FieldTypeTraits return Status::Error( "FieldTypeTraits::from_string meet PARSE_FAILURE"); } - *reinterpret_cast(buf) = value; + *reinterpret_cast(buf) = value; return Status::OK(); } static std::string to_string(const void* src) { - // TODO: support decimal256 - DCHECK(false); - return ""; - // auto value = reinterpret_cast(src); - // fmt::memory_buffer buffer; - // fmt::format_to(buffer, "{}", *value); - // return std::string(buffer.data(), buffer.size()); + const auto* value = reinterpret_cast(src); + return wide::to_string(*value); } }; diff --git a/be/src/runtime/type_limit.h b/be/src/runtime/type_limit.h index d406689644b8b2..374f4d9099f135 100644 --- a/be/src/runtime/type_limit.h +++ b/be/src/runtime/type_limit.h @@ -70,8 +70,8 @@ struct type_limit { } static vectorized::Decimal128 min() { return -max(); } }; -static Int256 MAX_DECIMAL256_INT({18446744073709551615ul, 8607968719199866879ul, - 532749306367912313ul, 1593091911132452277ul}); +static wide::Int256 MAX_DECIMAL256_INT({18446744073709551615ul, 8607968719199866879ul, + 532749306367912313ul, 1593091911132452277ul}); template <> struct type_limit { static vectorized::Decimal256 max() { return vectorized::Decimal256(MAX_DECIMAL256_INT); } diff --git a/be/src/util/string_parser.hpp b/be/src/util/string_parser.hpp index 2e0955977181bf..a37ffe9d147271 100644 --- a/be/src/util/string_parser.hpp +++ b/be/src/util/string_parser.hpp @@ -93,7 +93,7 @@ class StringParser { template static T get_scale_multiplier(int scale) { static_assert(std::is_same_v || std::is_same_v || - std::is_same_v || std::is_same_v, + std::is_same_v || std::is_same_v, "You can only instantiate as int32_t, int64_t, __int128."); if constexpr (std::is_same_v) { return common::exp10_i32(scale); @@ -101,7 +101,7 @@ class StringParser { return common::exp10_i64(scale); } else if constexpr (std::is_same_v) { return common::exp10_i128(scale); - } else if constexpr (std::is_same_v) { + } else if constexpr (std::is_same_v) { return common::exp10_i256(scale); } } diff --git a/be/src/vec/common/int_exp.h b/be/src/vec/common/int_exp.h index 81ca11bb11a10c..03829218f7f1ce 100644 --- a/be/src/vec/common/int_exp.h +++ b/be/src/vec/common/int_exp.h @@ -80,32 +80,30 @@ inline constexpr __int128 exp10_i128(int x) { return exp_details::get_exp<__int128, 10, 39>(x); } -using wide::Int256; -inline Int256 exp10_i256(int x) { +inline wide::Int256 exp10_i256(int x) { if (x < 0) return 0; - if (x > 76) return std::numeric_limits::max(); - - using Int256 = Int256; - static constexpr Int256 i10e18 {1000000000000000000ll}; - static const Int256 values[] = { - static_cast(1ll), - static_cast(10ll), - static_cast(100ll), - static_cast(1000ll), - static_cast(10000ll), - static_cast(100000ll), - static_cast(1000000ll), - static_cast(10000000ll), - static_cast(100000000ll), - static_cast(1000000000ll), - static_cast(10000000000ll), - static_cast(100000000000ll), - static_cast(1000000000000ll), - static_cast(10000000000000ll), - static_cast(100000000000000ll), - static_cast(1000000000000000ll), - static_cast(10000000000000000ll), - static_cast(100000000000000000ll), + if (x > 76) return std::numeric_limits::max(); + + static constexpr wide::Int256 i10e18 {1000000000000000000ll}; + static const wide::Int256 values[] = { + static_cast(1ll), + static_cast(10ll), + static_cast(100ll), + static_cast(1000ll), + static_cast(10000ll), + static_cast(100000ll), + static_cast(1000000ll), + static_cast(10000000ll), + static_cast(100000000ll), + static_cast(1000000000ll), + static_cast(10000000000ll), + static_cast(100000000000ll), + static_cast(1000000000000ll), + static_cast(10000000000000ll), + static_cast(100000000000000ll), + static_cast(1000000000000000ll), + static_cast(10000000000000000ll), + static_cast(100000000000000000ll), i10e18, i10e18 * 10ll, i10e18 * 100ll, diff --git a/be/src/vec/core/accurate_comparison.h b/be/src/vec/core/accurate_comparison.h index dc3d54ebb58725..71189d37d664ee 100644 --- a/be/src/vec/core/accurate_comparison.h +++ b/be/src/vec/core/accurate_comparison.h @@ -181,17 +181,17 @@ bool lessOp(A a, B b) { /// int vs int if constexpr (wide::is_integer && wide::is_integer) { /// same signedness - if constexpr (wide::is_signed_v == wide::is_signed_v) { + if constexpr (std::is_signed_v == std::is_signed_v) { return a < b; } /// different signedness - if constexpr (wide::is_signed_v && !wide::is_signed_v) { + if constexpr (std::is_signed_v && !std::is_signed_v) { return a < 0 || static_cast>(a) < b; } - if constexpr (!wide::is_signed_v && wide::is_signed_v) { + if constexpr (!std::is_signed_v && std::is_signed_v) { return b >= 0 && a < static_cast>(b); } } @@ -260,17 +260,17 @@ bool equalsOp(A a, B b) { /// int vs int if constexpr (wide::is_integer && wide::is_integer) { /// same signedness - if constexpr (wide::is_signed_v == wide::is_signed_v) { + if constexpr (std::is_signed_v == std::is_signed_v) { return a == b; } /// different signedness - if constexpr (wide::is_signed_v && !wide::is_signed_v) { + if constexpr (std::is_signed_v && !std::is_signed_v) { return a >= 0 && static_cast>(a) == b; } - if constexpr (!wide::is_signed_v && wide::is_signed_v) { + if constexpr (!std::is_signed_v && std::is_signed_v) { return b >= 0 && a == static_cast>(b); } } diff --git a/be/src/vec/core/decimal_comparison.h b/be/src/vec/core/decimal_comparison.h index 82cba4fe842aaf..46c6f729ca100f 100644 --- a/be/src/vec/core/decimal_comparison.h +++ b/be/src/vec/core/decimal_comparison.h @@ -56,7 +56,7 @@ struct ConstructDecInt<16> { }; template <> struct ConstructDecInt<32> { - using Type = Int256; + using Type = wide::Int256; }; template diff --git a/be/src/vec/core/decomposed_float.h b/be/src/vec/core/decomposed_float.h index bccfd0cb43df82..d7651145ae3de3 100644 --- a/be/src/vec/core/decomposed_float.h +++ b/be/src/vec/core/decomposed_float.h @@ -113,16 +113,16 @@ struct DecomposedFloat { } /// The case of the most negative integer - if constexpr (wide::is_signed_v) { + if constexpr (std::is_signed_v) { if (rhs == std::numeric_limits::lowest()) { assert(isNegative()); if (normalizedExponent() < - static_cast(8 * sizeof(Int) - wide::is_signed_v)) { + static_cast(8 * sizeof(Int) - std::is_signed_v)) { return 1; } if (normalizedExponent() > - static_cast(8 * sizeof(Int) - wide::is_signed_v)) { + static_cast(8 * sizeof(Int) - std::is_signed_v)) { return -1; } @@ -134,8 +134,7 @@ struct DecomposedFloat { } /// Too large number: abs(float) > abs(rhs). Also the case with infinities and NaN. - if (normalizedExponent() >= - static_cast(8 * sizeof(Int) - wide::is_signed_v)) { + if (normalizedExponent() >= static_cast(8 * sizeof(Int) - std::is_signed_v)) { return isNegative() ? -1 : 1; } @@ -151,7 +150,7 @@ struct DecomposedFloat { /// Larger octave: abs(rhs) > abs(float) if (normalizedExponent() + 1 < - static_cast(8 * sizeof(Int) - wide::is_signed_v) && + static_cast(8 * sizeof(Int) - std::is_signed_v) && uint_rhs >= (static_cast(1) << (normalizedExponent() + 1))) { return isNegative() ? 1 : -1; } diff --git a/be/src/vec/core/extended_types.h b/be/src/vec/core/extended_types.h index d14e9673da699e..5ecbad0bc785ec 100644 --- a/be/src/vec/core/extended_types.h +++ b/be/src/vec/core/extended_types.h @@ -23,60 +23,48 @@ #include "wide_integer.h" -using Int256 = wide::integer<256, signed>; -using UInt256 = wide::integer<256, unsigned>; - -static_assert(sizeof(Int256) == 32); -static_assert(sizeof(UInt256) == 32); +static_assert(sizeof(wide::Int256) == 32); +static_assert(sizeof(wide::UInt256) == 32); /// The standard library type traits, such as std::is_arithmetic, with one exception /// (std::common_type), are "set in stone". Attempting to specialize them causes undefined behavior. /// So instead of using the std type_traits, we use our own version which allows extension. namespace wide { -template -struct is_signed // NOLINT(readability-identifier-naming) -{ - static constexpr bool value = std::is_signed_v; -}; - +template +concept is_integer = std::is_integral_v || std::is_same_v || + std::is_same_v; +} template <> -struct is_signed { +struct std::is_signed { static constexpr bool value = true; }; - -template -inline constexpr bool is_signed_v = is_signed::value; - -template -struct is_unsigned // NOLINT(readability-identifier-naming) -{ - static constexpr bool value = std::is_unsigned_v; +template <> +struct std::is_signed { + static constexpr bool value = false; }; -template -inline constexpr bool is_unsigned_v = is_unsigned::value; - -template -concept is_integer = - std::is_integral_v || std::is_same_v || std::is_same_v; -} // namespace wide - -namespace std { template <> -struct make_unsigned { - using type = UInt256; +struct std::is_unsigned { + static constexpr bool value = false; }; template <> -struct make_unsigned { - using type = UInt256; +struct std::is_unsigned { + static constexpr bool value = true; }; - template <> -struct make_signed { - using type = Int256; +struct std::make_unsigned { + using type = wide::UInt256; }; template <> -struct make_signed { - using type = Int256; +struct std::make_unsigned { + using type = wide::UInt256; }; -} // namespace std \ No newline at end of file + +template <> +struct std::make_signed { + using type = wide::Int256; +}; +template <> +struct std::make_signed { + using type = wide::Int256; +}; \ No newline at end of file diff --git a/be/src/vec/core/field.h b/be/src/vec/core/field.h index 026de2d54e18a1..339776d654be3e 100644 --- a/be/src/vec/core/field.h +++ b/be/src/vec/core/field.h @@ -828,7 +828,7 @@ struct Field::TypeToEnum { static constexpr Types::Which value = Types::Int128; }; template <> -struct Field::TypeToEnum { +struct Field::TypeToEnum { static constexpr Types::Which value = Types::Int256; }; template <> diff --git a/be/src/vec/core/types.h b/be/src/vec/core/types.h index 861126a030ed42..9bf289787d26d6 100644 --- a/be/src/vec/core/types.h +++ b/be/src/vec/core/types.h @@ -32,8 +32,6 @@ #include "vec/core/wide_integer.h" #include "vec/core/wide_integer_to_string.h" -using wide::Int256; - namespace doris { class BitmapValue; @@ -290,9 +288,9 @@ struct TypeName { static const char* get() { return "Int128"; } }; template <> -inline constexpr bool IsNumber = true; +inline constexpr bool IsNumber = true; template <> -struct TypeName { +struct TypeName { static const char* get() { return "Int256"; } }; template <> @@ -301,7 +299,7 @@ struct TypeId { }; template <> -struct TypeId { +struct TypeId { static constexpr const TypeIndex value = TypeIndex::Int256; }; @@ -326,7 +324,7 @@ inline constexpr Int128 decimal_scale_multiplier(UInt32 scale) { } // gcc report error if add constexpr in declaration template <> -inline Int256 decimal_scale_multiplier(UInt32 scale) { +inline wide::Int256 decimal_scale_multiplier(UInt32 scale) { return common::exp10_i256(scale); } @@ -345,7 +343,7 @@ struct Decimal { #define DECLARE_NUMERIC_CTOR(TYPE) \ Decimal(const TYPE& value_) : value(value_) {} - DECLARE_NUMERIC_CTOR(Int256) + DECLARE_NUMERIC_CTOR(wide::Int256) DECLARE_NUMERIC_CTOR(Int128) DECLARE_NUMERIC_CTOR(Int32) DECLARE_NUMERIC_CTOR(Int64) @@ -434,7 +432,7 @@ struct Decimal { std::string to_string(UInt32 scale) const { if (value == std::numeric_limits::min()) { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { std::string res {wide::to_string(value)}; res.insert(res.size() - scale, "."); return res; @@ -475,7 +473,7 @@ struct Decimal { whole_part = abs_value / decimal_scale_multiplier(scale); frac_part = abs_value % decimal_scale_multiplier(scale); } - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { std::string num_str {wide::to_string(whole_part)}; auto end = fmt::format_to(str.data() + pos, "{}", num_str); pos = end - str.data(); @@ -506,7 +504,7 @@ struct Decimal { __attribute__((always_inline)) size_t to_string(char* dst, UInt32 scale, const T& scale_multiplier) const { if (UNLIKELY(value == std::numeric_limits::min())) { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { // handle scale? std::string num_str {wide::to_string(value)}; auto end = fmt::format_to(dst, "{}", num_str); @@ -532,7 +530,7 @@ struct Decimal { whole_part = abs_value / scale_multiplier; frac_part = abs_value % scale_multiplier; } - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { std::string num_str {wide::to_string(whole_part)}; auto end = fmt::format_to(dst + pos, "{}", num_str); pos = end - dst; @@ -559,7 +557,7 @@ struct Decimal { pos += scale - low_scale; } if (frac_part) { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { std::string num_str {wide::to_string(whole_part)}; auto end = fmt::format_to(&dst[pos], "{}", num_str); pos = end - dst; @@ -582,7 +580,7 @@ struct Decimal128I : public Decimal { #define DECLARE_NUMERIC_CTOR(TYPE) \ Decimal128I(const TYPE& value_) : Decimal(value_) {} - DECLARE_NUMERIC_CTOR(Int256) + DECLARE_NUMERIC_CTOR(wide::Int256) DECLARE_NUMERIC_CTOR(Int128) DECLARE_NUMERIC_CTOR(Int32) DECLARE_NUMERIC_CTOR(Int64) @@ -599,9 +597,9 @@ struct Decimal128I : public Decimal { }; template <> -struct Decimal { - using T = Int256; - using NativeType = Int256; +struct Decimal { + using T = wide::Int256; + using NativeType = wide::Int256; Decimal() = default; Decimal(Decimal&&) = default; @@ -610,7 +608,7 @@ struct Decimal { #define DECLARE_NUMERIC_CTOR(TYPE) \ explicit Decimal(const TYPE& value_) : value(value_) {} - DECLARE_NUMERIC_CTOR(Int256) + DECLARE_NUMERIC_CTOR(wide::Int256) DECLARE_NUMERIC_CTOR(Int128) DECLARE_NUMERIC_CTOR(Int32) DECLARE_NUMERIC_CTOR(Int64) @@ -694,7 +692,7 @@ struct Decimal { std::string to_string(UInt32 scale) const { if (value == std::numeric_limits::min()) { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { std::string res {wide::to_string(value)}; res.insert(res.size() - scale, "."); return res; @@ -735,7 +733,7 @@ struct Decimal { whole_part = abs_value / decimal_scale_multiplier(scale); frac_part = abs_value % decimal_scale_multiplier(scale); } - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { std::string num_str {wide::to_string(whole_part)}; auto end = fmt::format_to(str.data() + pos, "{}", num_str); pos = end - str.data(); @@ -766,7 +764,7 @@ struct Decimal { __attribute__((always_inline)) size_t to_string(char* dst, UInt32 scale, const T& scale_multiplier) const { if (UNLIKELY(value == std::numeric_limits::min())) { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { std::string num_str {wide::to_string(value)}; auto end = fmt::format_to(dst, "{}", num_str); return end - dst; @@ -791,7 +789,7 @@ struct Decimal { whole_part = abs_value / scale_multiplier; frac_part = abs_value % scale_multiplier; } - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { std::string num_str {wide::to_string(whole_part)}; auto end = fmt::format_to(dst + pos, "{}", num_str); pos = end - dst; @@ -818,7 +816,7 @@ struct Decimal { pos += scale - low_scale; } if (frac_part) { - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { std::string num_str {wide::to_string(frac_part)}; auto end = fmt::format_to(dst + pos, "{}", num_str); pos = end - dst; @@ -838,7 +836,7 @@ struct Decimal { using Decimal32 = Decimal; using Decimal64 = Decimal; using Decimal128 = Decimal; -using Decimal256 = Decimal; +using Decimal256 = Decimal; template inline Decimal operator-(const Decimal& x) { return -x.value; @@ -993,7 +991,7 @@ struct NativeType { }; template <> struct NativeType { - using Type = Int256; + using Type = wide::Int256; }; inline const char* getTypeName(TypeIndex idx) { @@ -1021,7 +1019,7 @@ inline const char* getTypeName(TypeIndex idx) { case TypeIndex::Int128: return TypeName::get(); case TypeIndex::Int256: - return TypeName::get(); + return TypeName::get(); case TypeIndex::Float32: return TypeName::get(); case TypeIndex::Float64: diff --git a/be/src/vec/data_types/data_type_decimal.h b/be/src/vec/data_types/data_type_decimal.h index 35b87afcabd331..9cafe0e3a17a23 100644 --- a/be/src/vec/data_types/data_type_decimal.h +++ b/be/src/vec/data_types/data_type_decimal.h @@ -612,7 +612,7 @@ ToDataType::FieldType convert_to_decimal(const typename FromDataType::FieldType& return convert_decimals, ToDataType>(value, 0, scale); } - if constexpr (std::is_same_v) { + if constexpr (std::is_same_v) { return convert_decimals, ToDataType>(value, 0, scale); } return convert_decimals, ToDataType>(value, 0, scale); diff --git a/fe/fe-common/src/main/java/org/apache/doris/catalog/ArrayType.java b/fe/fe-common/src/main/java/org/apache/doris/catalog/ArrayType.java index a2915fb4b495e4..8edcfb517300e5 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/catalog/ArrayType.java +++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/ArrayType.java @@ -104,7 +104,7 @@ public boolean hasTemplateType() { @Override public Type specializeTemplateType(Type specificType, Map specializedTypeMap, - boolean useSpecializedType) throws TypeException { + boolean useSpecializedType, boolean enableDecimal256) throws TypeException { ArrayType specificArrayType = null; if (specificType instanceof ArrayType) { specificArrayType = (ArrayType) specificType; @@ -116,7 +116,7 @@ public Type specializeTemplateType(Type specificType, Map speciali if (itemType.hasTemplateType()) { newItemType = itemType.specializeTemplateType( specificArrayType != null ? specificArrayType.itemType : specificType, - specializedTypeMap, useSpecializedType); + specializedTypeMap, useSpecializedType, enableDecimal256); } return new ArrayType(newItemType); @@ -163,8 +163,10 @@ public static boolean canCastTo(ArrayType type, ArrayType targetType) { return Type.canCastTo(type.getItemType(), targetType.getItemType()); } - public static Type getAssignmentCompatibleType(ArrayType t1, ArrayType t2, boolean strict) { - Type itemCompatibleType = Type.getAssignmentCompatibleType(t1.getItemType(), t2.getItemType(), strict); + public static Type getAssignmentCompatibleType( + ArrayType t1, ArrayType t2, boolean strict, boolean enableDecimal256) { + Type itemCompatibleType = Type.getAssignmentCompatibleType(t1.getItemType(), t2.getItemType(), strict, + enableDecimal256); if (itemCompatibleType.isInvalid()) { return ScalarType.INVALID; diff --git a/fe/fe-common/src/main/java/org/apache/doris/catalog/MapType.java b/fe/fe-common/src/main/java/org/apache/doris/catalog/MapType.java index 06dba8c2fb0219..e6ab17c626ba77 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/catalog/MapType.java +++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/MapType.java @@ -142,7 +142,7 @@ public boolean hasTemplateType() { @Override public Type specializeTemplateType(Type specificType, Map specializedTypeMap, - boolean useSpecializedType) throws TypeException { + boolean useSpecializedType, boolean enableDecimal256) throws TypeException { MapType specificMapType = null; if (specificType instanceof MapType) { specificMapType = (MapType) specificType; @@ -154,13 +154,13 @@ public Type specializeTemplateType(Type specificType, Map speciali if (keyType.hasTemplateType()) { newKeyType = keyType.specializeTemplateType( specificMapType != null ? specificMapType.keyType : specificType, - specializedTypeMap, useSpecializedType); + specializedTypeMap, useSpecializedType, enableDecimal256); } Type newValueType = valueType; if (valueType.hasTemplateType()) { newValueType = valueType.specializeTemplateType( specificMapType != null ? specificMapType.valueType : specificType, - specializedTypeMap, useSpecializedType); + specializedTypeMap, useSpecializedType, enableDecimal256); } Type newMapType = new MapType(newKeyType, newValueType); @@ -198,12 +198,14 @@ public static boolean canCastTo(MapType type, MapType targetType) { || targetType.getValueType().isStringType() && type.getValueType().isStringType()); } - public static Type getAssignmentCompatibleType(MapType t1, MapType t2, boolean strict) { - Type keyCompatibleType = Type.getAssignmentCompatibleType(t1.getKeyType(), t2.getKeyType(), strict); + public static Type getAssignmentCompatibleType(MapType t1, MapType t2, boolean strict, boolean enableDecimal256) { + Type keyCompatibleType = Type.getAssignmentCompatibleType(t1.getKeyType(), t2.getKeyType(), strict, + enableDecimal256); if (keyCompatibleType.isInvalid()) { return ScalarType.INVALID; } - Type valCompatibleType = Type.getAssignmentCompatibleType(t1.getValueType(), t2.getValueType(), strict); + Type valCompatibleType = Type.getAssignmentCompatibleType(t1.getValueType(), t2.getValueType(), strict, + enableDecimal256); if (valCompatibleType.isInvalid()) { return ScalarType.INVALID; } diff --git a/fe/fe-common/src/main/java/org/apache/doris/catalog/ScalarType.java b/fe/fe-common/src/main/java/org/apache/doris/catalog/ScalarType.java index 3bd7f7a7e0b8ea..492cb8e15b60f5 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/catalog/ScalarType.java +++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/ScalarType.java @@ -1019,7 +1019,7 @@ public boolean isSupertypeOf(ScalarType o) { * is INVALID_TYPE. */ public static ScalarType getAssignmentCompatibleType( - ScalarType t1, ScalarType t2, boolean strict) { + ScalarType t1, ScalarType t2, boolean strict, boolean enableDecimal256) { if (!t1.isValid() || !t2.isValid()) { return INVALID; } @@ -1119,7 +1119,11 @@ public static ScalarType getAssignmentCompatibleType( if (scale + integerPart <= ScalarType.MAX_DECIMAL128_PRECISION) { return ScalarType.createDecimalV3Type(scale + integerPart, scale); } else { - return Type.DOUBLE; + if (enableDecimal256) { + return ScalarType.createDecimalV3Type(scale + integerPart, scale); + } else { + return Type.DOUBLE; + } } } @@ -1177,8 +1181,8 @@ public static ScalarType getAssignmentCompatibleDecimalV3Type(ScalarType t1, Sca * If strict is true, only consider casts that result in no loss of precision. */ public static boolean isImplicitlyCastable( - ScalarType t1, ScalarType t2, boolean strict) { - return getAssignmentCompatibleType(t1, t2, strict).matchesType(t2); + ScalarType t1, ScalarType t2, boolean strict, boolean enableDecimal256) { + return getAssignmentCompatibleType(t1, t2, strict, enableDecimal256).matchesType(t2); } public static boolean canCastTo(ScalarType type, ScalarType targetType) { diff --git a/fe/fe-common/src/main/java/org/apache/doris/catalog/StructType.java b/fe/fe-common/src/main/java/org/apache/doris/catalog/StructType.java index 1d6be19d28efbc..4f21286c63699a 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/catalog/StructType.java +++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/StructType.java @@ -111,7 +111,8 @@ public static boolean canCastTo(StructType type, StructType targetType) { return true; } - public static Type getAssignmentCompatibleType(StructType t1, StructType t2, boolean strict) { + public static Type getAssignmentCompatibleType( + StructType t1, StructType t2, boolean strict, boolean enableDecimal256) { ArrayList fieldsLeft = t1.getFields(); ArrayList fieldsRight = t2.getFields(); ArrayList fieldsRes = new ArrayList<>(); @@ -120,7 +121,7 @@ public static Type getAssignmentCompatibleType(StructType t1, StructType t2, boo StructField leftField = fieldsLeft.get(i); StructField rightField = fieldsRight.get(i); Type itemCompatibleType = Type.getAssignmentCompatibleType(leftField.getType(), rightField.getType(), - strict); + strict, enableDecimal256); if (itemCompatibleType.isInvalid()) { return ScalarType.INVALID; } @@ -221,7 +222,7 @@ public boolean hasTemplateType() { @Override public Type specializeTemplateType(Type specificType, Map specializedTypeMap, - boolean useSpecializedType) throws TypeException { + boolean useSpecializedType, boolean enableDecimal256) throws TypeException { StructType specificStructType = null; if (specificType instanceof StructType) { specificStructType = (StructType) specificType; @@ -234,7 +235,7 @@ public Type specializeTemplateType(Type specificType, Map speciali if (fields.get(i).type.hasTemplateType()) { newTypes.add(fields.get(i).type.specializeTemplateType( specificStructType != null ? specificStructType.fields.get(i).type : specificType, - specializedTypeMap, useSpecializedType)); + specializedTypeMap, useSpecializedType, enableDecimal256)); } } diff --git a/fe/fe-common/src/main/java/org/apache/doris/catalog/TemplateType.java b/fe/fe-common/src/main/java/org/apache/doris/catalog/TemplateType.java index 661591860105e7..ba5ed62f9d0fdf 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/catalog/TemplateType.java +++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/TemplateType.java @@ -81,7 +81,7 @@ public boolean needExpandTemplateType() { @Override public Type specializeTemplateType(Type specificType, Map specializedTypeMap, - boolean useSpecializedType) throws TypeException { + boolean useSpecializedType, boolean enableDecimal256) throws TypeException { if (specificType.hasTemplateType() && !specificType.isNull()) { throw new TypeException(specificType + " should not hasTemplateType"); } @@ -97,7 +97,7 @@ public Type specializeTemplateType(Type specificType, Map speciali if (specializedType != null && !specificType.equals(specializedType) && !specificType.matchesType(specializedType) - && !Type.isImplicitlyCastable(specificType, specializedType, true) + && !Type.isImplicitlyCastable(specificType, specializedType, true, enableDecimal256) && !Type.canCastTo(specificType, specializedType)) { throw new TypeException( String.format("can not specialize template type %s to %s since it's already specialized as %s", diff --git a/fe/fe-common/src/main/java/org/apache/doris/catalog/Type.java b/fe/fe-common/src/main/java/org/apache/doris/catalog/Type.java index 8091858e249264..091c274f3eb6a1 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/catalog/Type.java +++ b/fe/fe-common/src/main/java/org/apache/doris/catalog/Type.java @@ -627,7 +627,7 @@ public boolean needExpandTemplateType() { // return a new type without template type, by specialize template type in this type public Type specializeTemplateType(Type specificType, Map specializedTypeMap, - boolean useSpecializedType) throws TypeException { + boolean useSpecializedType, boolean enableDecimal256) throws TypeException { if (hasTemplateType()) { // throw exception by default, sub class should specialize tempalte type properly throw new TypeException("specializeTemplateType not implemented"); @@ -728,9 +728,9 @@ public boolean matchesType(Type t) { * If strict is true, only consider casts that result in no loss of precision. * TODO: Support casting of non-scalar types. */ - public static boolean isImplicitlyCastable(Type t1, Type t2, boolean strict) { + public static boolean isImplicitlyCastable(Type t1, Type t2, boolean strict, boolean enableDecimal256) { if (t1.isScalarType() && t2.isScalarType()) { - return ScalarType.isImplicitlyCastable((ScalarType) t1, (ScalarType) t2, strict); + return ScalarType.isImplicitlyCastable((ScalarType) t1, (ScalarType) t2, strict, enableDecimal256); } if (t1.isComplexType() || t2.isComplexType()) { if ((t1.isArrayType() && t2.isArrayType()) || (t1.isMapType() && t2.isMapType()) @@ -771,17 +771,17 @@ public static boolean canCastTo(Type sourceType, Type targetType) { * no such type or if any of t1 and t2 is INVALID_TYPE. * TODO: Support non-scalar types. */ - public static Type getAssignmentCompatibleType(Type t1, Type t2, boolean strict) { + public static Type getAssignmentCompatibleType(Type t1, Type t2, boolean strict, boolean enableDecimal256) { if (t1.isScalarType() && t2.isScalarType()) { - return ScalarType.getAssignmentCompatibleType((ScalarType) t1, (ScalarType) t2, strict); + return ScalarType.getAssignmentCompatibleType((ScalarType) t1, (ScalarType) t2, strict, enableDecimal256); } if (t1.isArrayType() && t2.isArrayType()) { - return ArrayType.getAssignmentCompatibleType((ArrayType) t1, (ArrayType) t2, strict); + return ArrayType.getAssignmentCompatibleType((ArrayType) t1, (ArrayType) t2, strict, enableDecimal256); } else if (t1.isMapType() && t2.isMapType()) { - return MapType.getAssignmentCompatibleType((MapType) t1, (MapType) t2, strict); + return MapType.getAssignmentCompatibleType((MapType) t1, (MapType) t2, strict, enableDecimal256); } else if (t1.isStructType() && t2.isStructType()) { - return StructType.getAssignmentCompatibleType((StructType) t1, (StructType) t2, strict); + return StructType.getAssignmentCompatibleType((StructType) t1, (StructType) t2, strict, enableDecimal256); } else if (t1.isComplexType() && t2.isNull()) { return t1; } else if (t1.isNull() && t2.isComplexType()) { @@ -1977,7 +1977,7 @@ public Type getResultType() { } } - public static Type getCmpType(Type t1, Type t2) { + public static Type getCmpType(Type t1, Type t2, boolean enableDecimal256) { if (t1.getPrimitiveType() == PrimitiveType.NULL_TYPE) { return t2; } @@ -2033,7 +2033,7 @@ public static Type getCmpType(Type t1, Type t2) { } if (t1ResultType == PrimitiveType.BIGINT && t2ResultType == PrimitiveType.BIGINT) { - return getAssignmentCompatibleType(t1, t2, false); + return getAssignmentCompatibleType(t1, t2, false, enableDecimal256); } if (t1.getPrimitiveType().isDecimalV3Type() && t2.getPrimitiveType().isDecimalV3Type()) { int resultPrecision = Math.max(t1.getPrecision(), t2.getPrecision()); @@ -2049,11 +2049,16 @@ public static Type getCmpType(Type t1, Type t2) { return ScalarType.createDecimalType(resultDecimalType, resultPrecision, Math.max( ((ScalarType) t1).getScalarScale(), ((ScalarType) t2).getScalarScale())); } else { - return Type.DOUBLE; + if (enableDecimal256) { + return ScalarType.createDecimalType(resultDecimalType, resultPrecision, Math.max( + ((ScalarType) t1).getScalarScale(), ((ScalarType) t2).getScalarScale())); + } else { + return Type.DOUBLE; + } } } if (t1ResultType.isDecimalV3Type() || t2ResultType.isDecimalV3Type()) { - return getAssignmentCompatibleType(t1, t2, false); + return getAssignmentCompatibleType(t1, t2, false, enableDecimal256); } if ((t1ResultType == PrimitiveType.BIGINT || t1ResultType == PrimitiveType.DECIMALV2) diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyticExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyticExpr.java index 2271fc871ac86b..37b4684f1569c0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyticExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyticExpr.java @@ -30,6 +30,7 @@ import org.apache.doris.common.AnalysisException; import org.apache.doris.common.TreeNode; import org.apache.doris.nereids.util.Utils; +import org.apache.doris.qe.SessionVariable; import org.apache.doris.thrift.TExprNode; import com.google.common.base.Joiner; @@ -361,7 +362,8 @@ private void checkRangeOffsetBoundaryExpr(AnalyticWindow.Boundary boundary) thro Expr rangeExpr = boundary.getExpr(); if (!Type.isImplicitlyCastable( - rangeExpr.getType(), orderByElements.get(0).getExpr().getType(), false)) { + rangeExpr.getType(), orderByElements.get(0).getExpr().getType(), false, + SessionVariable.getEnableDecimal256())) { throw new AnalysisException( "The value expression of a PRECEDING/FOLLOWING clause of a RANGE window must " + "be implicitly convertible to the ORDER BY expression's type: " diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java index e93d622df5ddee..99c436aeb1237c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/Analyzer.java @@ -45,6 +45,7 @@ import org.apache.doris.planner.PlanNode; import org.apache.doris.planner.RuntimeFilter; import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.SessionVariable; import org.apache.doris.rewrite.BetweenToCompoundRule; import org.apache.doris.rewrite.CompoundPredicateWriteRule; import org.apache.doris.rewrite.EliminateUnnecessaryFunctions; @@ -2155,7 +2156,8 @@ public Type getCompatibleType(Type lastCompatibleType, Expr lastCompatibleExpr, if (lastCompatibleType == null) { newCompatibleType = expr.getType(); } else { - newCompatibleType = Type.getAssignmentCompatibleType(lastCompatibleType, expr.getType(), false); + newCompatibleType = Type.getAssignmentCompatibleType( + lastCompatibleType, expr.getType(), false, SessionVariable.getEnableDecimal256()); } if (!newCompatibleType.isValid()) { throw new AnalysisException(String.format( @@ -2177,15 +2179,16 @@ public Type castAllToCompatibleType(List exprs) throws AnalysisException { Type compatibleType = exprs.get(0).getType(); for (int i = 1; i < exprs.size(); ++i) { exprs.get(i).analyze(this); + boolean enableDecimal256 = SessionVariable.getEnableDecimal256(); if (compatibleType.isDateV2() && exprs.get(i) instanceof StringLiteral && ((StringLiteral) exprs.get(i)).canConvertToDateType(compatibleType)) { // If string literal can be converted to dateV2, we use datev2 as the compatible type // instead of datetimev2. } else if (exprs.get(i).isConstantImpl()) { exprs.get(i).compactForLiteral(compatibleType); - compatibleType = Type.getCmpType(compatibleType, exprs.get(i).getType()); + compatibleType = Type.getCmpType(compatibleType, exprs.get(i).getType(), enableDecimal256); } else { - compatibleType = Type.getCmpType(compatibleType, exprs.get(i).getType()); + compatibleType = Type.getCmpType(compatibleType, exprs.get(i).getType(), enableDecimal256); } } if (compatibleType.equals(Type.VARCHAR)) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ArithmeticExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ArithmeticExpr.java index cf74b9b4874720..cdd8a20dec221c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ArithmeticExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ArithmeticExpr.java @@ -31,6 +31,7 @@ import org.apache.doris.common.Config; import org.apache.doris.common.io.Text; import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.SessionVariable; import org.apache.doris.thrift.TExprNode; import org.apache.doris.thrift.TExprNodeType; import org.apache.doris.thrift.TExprOpcode; @@ -111,7 +112,8 @@ public static void initBuiltins(FunctionSet functionSet) { for (int j = 0; j < Type.getNumericTypes().size(); j++) { Type t2 = Type.getNumericTypes().get(j); - Type retType = Type.getNextNumType(Type.getAssignmentCompatibleType(t1, t2, false)); + // For old planner, set enableDecimal256 to false to keep the original behaviour + Type retType = Type.getNextNumType(Type.getAssignmentCompatibleType(t1, t2, false, false)); NullableMode mode = retType.isDecimalV3() ? NullableMode.CUSTOM : NullableMode.DEPEND_ON_ARGUMENT; functionSet.addBuiltin(ScalarFunction.createBuiltinOperator( Operator.MULTIPLY.getName(), Lists.newArrayList(t1, t2), retType, mode)); @@ -197,13 +199,14 @@ public static void initBuiltins(FunctionSet functionSet) { for (int j = 0; j < Type.getIntegerTypes().size(); j++) { Type t2 = Type.getIntegerTypes().get(j); + // For old planner, set enableDecimal256 to false to keep the original behaviour functionSet.addBuiltin(ScalarFunction.createBuiltinOperator( Operator.INT_DIVIDE.getName(), Lists.newArrayList(t1, t2), - Type.getAssignmentCompatibleType(t1, t2, false), + Type.getAssignmentCompatibleType(t1, t2, false, false), Function.NullableMode.ALWAYS_NULLABLE)); functionSet.addBuiltin(ScalarFunction.createBuiltinOperator( Operator.MOD.getName(), Lists.newArrayList(t1, t2), - Type.getAssignmentCompatibleType(t1, t2, false), + Type.getAssignmentCompatibleType(t1, t2, false, false), Function.NullableMode.ALWAYS_NULLABLE)); } } @@ -401,7 +404,7 @@ private void analyzeNoneDecimalOp(Type t1, Type t2) throws AnalysisException { t1 = Type.TINYINT; t2 = Type.TINYINT; } - commonType = Type.getAssignmentCompatibleType(t1, t2, false); + commonType = Type.getAssignmentCompatibleType(t1, t2, false, SessionVariable.getEnableDecimal256()); if (commonType.getPrimitiveType().ordinal() > PrimitiveType.LARGEINT.ordinal()) { commonType = Type.BIGINT; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ArrayLiteral.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ArrayLiteral.java index 37245ed52460f0..d73c4036c9573c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ArrayLiteral.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ArrayLiteral.java @@ -53,7 +53,7 @@ public ArrayLiteral(LiteralExpr... exprs) throws AnalysisException { if (itemType == Type.NULL) { itemType = expr.getType(); } else { - itemType = Type.getAssignmentCompatibleType(itemType, expr.getType(), false); + itemType = Type.getAssignmentCompatibleType(itemType, expr.getType(), false, false); } if (expr.isNullable()) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/BinaryPredicate.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/BinaryPredicate.java index 3064065539ea01..5996b299603a60 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/BinaryPredicate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/BinaryPredicate.java @@ -33,6 +33,7 @@ import org.apache.doris.common.Reference; import org.apache.doris.common.io.Text; import org.apache.doris.common.io.Writable; +import org.apache.doris.qe.SessionVariable; import org.apache.doris.thrift.TExprNode; import org.apache.doris.thrift.TExprNodeType; import org.apache.doris.thrift.TExprOpcode; @@ -447,7 +448,8 @@ private Type getCmpType() throws AnalysisException { return Type.STRING; } if (t1 == PrimitiveType.BIGINT && t2 == PrimitiveType.BIGINT) { - return Type.getAssignmentCompatibleType(getChild(0).getType(), getChild(1).getType(), false); + return Type.getAssignmentCompatibleType(getChild(0).getType(), getChild(1).getType(), false, + SessionVariable.getEnableDecimal256()); } if ((t1 == PrimitiveType.BIGINT && t2 == PrimitiveType.DECIMALV2) || (t2 == PrimitiveType.BIGINT && t1 == PrimitiveType.DECIMALV2) @@ -480,7 +482,8 @@ private Type getCmpType() throws AnalysisException { if ((t1.isDecimalV3Type() && !t2.isStringType() && !t2.isFloatingPointType()) || (t2.isDecimalV3Type() && !t1.isStringType() && !t1.isFloatingPointType())) { - return Type.getAssignmentCompatibleType(getChild(0).getType(), getChild(1).getType(), false); + return Type.getAssignmentCompatibleType(getChild(0).getType(), getChild(1).getType(), false, + SessionVariable.getEnableDecimal256()); } return Type.DOUBLE; diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java index 05dd3b7f904542..4beaf526386fb0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DateLiteral.java @@ -27,6 +27,7 @@ import org.apache.doris.common.InvalidFormatException; import org.apache.doris.nereids.util.DateUtils; import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.SessionVariable; import org.apache.doris.thrift.TDateLiteral; import org.apache.doris.thrift.TExprNode; import org.apache.doris.thrift.TExprNodeType; @@ -716,7 +717,7 @@ protected Expr uncheckedCastTo(Type targetType) throws AnalysisException { long value = getYear() * 1000 + getMonth() * 100 + getDay(); return new IntLiteral(value, Type.BIGINT); } else { - if (Type.isImplicitlyCastable(this.type, targetType, true)) { + if (Type.isImplicitlyCastable(this.type, targetType, true, SessionVariable.getEnableDecimal256())) { return new CastExpr(targetType, this); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/DecimalLiteral.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/DecimalLiteral.java index 0d781bff7b8d2a..0762f3191f5e20 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/DecimalLiteral.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/DecimalLiteral.java @@ -213,6 +213,7 @@ public ByteBuffer getHashValue(PrimitiveType type) { buffer.putLong(value.unscaledValue().longValue()); break; case DECIMAL128: + case DECIMAL256: LargeIntLiteral tmp = new LargeIntLiteral(value.unscaledValue()); return tmp.getHashValue(type); default: diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java index f0558e5333d652..5b7479ae2d41b6 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java @@ -40,6 +40,7 @@ import org.apache.doris.common.io.Writable; import org.apache.doris.nereids.util.Utils; import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.SessionVariable; import org.apache.doris.rewrite.mvrewrite.MVExprEquivalent; import org.apache.doris.statistics.ExprStats; import org.apache.doris.thrift.TExpr; @@ -1059,7 +1060,7 @@ public static Type getAssignmentCompatibleType(List children) { } assignmentCompatibleType = assignmentCompatibleType.isInvalid() ? children.get(i).type : ScalarType.getAssignmentCompatibleType(assignmentCompatibleType, children.get(i).type, - true); + true, SessionVariable.getEnableDecimal256()); } return assignmentCompatibleType; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java index a9fa0183421029..6fbb35aac6d325 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java @@ -41,6 +41,7 @@ import org.apache.doris.mysql.privilege.PrivPredicate; import org.apache.doris.nereids.util.Utils; import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.SessionVariable; import org.apache.doris.thrift.TExprNode; import org.apache.doris.thrift.TExprNodeType; @@ -1238,6 +1239,7 @@ private void analyzeBuiltinAggFunction(Analyzer analyzer) throws AnalysisExcepti } private void analyzeArrayFunction(Analyzer analyzer) throws AnalysisException { + boolean enableDecimal256 = SessionVariable.getEnableDecimal256(); if (fnName.getFunction().equalsIgnoreCase("array_distinct") || fnName.getFunction().equalsIgnoreCase("array_max") || fnName.getFunction().equalsIgnoreCase("array_min") @@ -1254,7 +1256,8 @@ private void analyzeArrayFunction(Analyzer analyzer) throws AnalysisException { Type[] childTypes = collectChildReturnTypes(); Type compatibleType = childTypes[0]; for (int i = 1; i < childTypes.length; ++i) { - compatibleType = Type.getAssignmentCompatibleType(compatibleType, childTypes[i], true); + compatibleType = Type.getAssignmentCompatibleType(compatibleType, childTypes[i], true, + enableDecimal256); if (compatibleType == Type.INVALID) { throw new AnalysisException(getFunctionNotFoundError(collectChildReturnTypes())); } @@ -1291,7 +1294,8 @@ private void analyzeArrayFunction(Analyzer analyzer) throws AnalysisException { } Type compatibleType = ((ArrayType) childTypes[0]).getItemType(); for (int i = 1; i < childTypes.length; ++i) { - compatibleType = Type.getAssignmentCompatibleType(compatibleType, childTypes[i], true); + compatibleType = Type.getAssignmentCompatibleType(compatibleType, childTypes[i], true, + enableDecimal256); if (compatibleType == Type.INVALID) { throw new AnalysisException(getFunctionNotFoundError(collectChildReturnTypes())); } @@ -1391,6 +1395,7 @@ public void analyzeImpl(Analyzer analyzer) throws AnalysisException { analyzeArrayFunction(analyzer); + boolean enableDecimal256 = SessionVariable.getEnableDecimal256(); if (fnName.getFunction().equalsIgnoreCase("sum")) { if (this.children.isEmpty()) { throw new AnalysisException("The " + fnName + " function must has one input param"); @@ -1403,7 +1408,7 @@ public void analyzeImpl(Analyzer analyzer) throws AnalysisException { Type compatibleType = this.children.get(0).getType(); for (int i = 1; i < this.children.size(); ++i) { Type type = this.children.get(i).getType(); - compatibleType = Type.getAssignmentCompatibleType(compatibleType, type, true); + compatibleType = Type.getAssignmentCompatibleType(compatibleType, type, true, enableDecimal256); if (compatibleType.isInvalid()) { compatibleType = Type.VARCHAR; break; @@ -1495,7 +1500,8 @@ public void analyzeImpl(Analyzer analyzer) throws AnalysisException { Function.CompareMode.IS_NONSTRICT_SUPERTYPE_OF); } else if (fnName.getFunction().equalsIgnoreCase("if")) { Type[] childTypes = collectChildReturnTypes(); - Type assignmentCompatibleType = ScalarType.getAssignmentCompatibleType(childTypes[1], childTypes[2], true); + Type assignmentCompatibleType = ScalarType.getAssignmentCompatibleType(childTypes[1], childTypes[2], true, + enableDecimal256); if (assignmentCompatibleType.isDecimalV3()) { if (assignmentCompatibleType.isDecimalV3() && !childTypes[1].equals(assignmentCompatibleType)) { uncheckedCastChild(assignmentCompatibleType, 1); @@ -1521,7 +1527,8 @@ public void analyzeImpl(Analyzer analyzer) throws AnalysisException { } else if (fnName.getFunction().equalsIgnoreCase("ifnull") || fnName.getFunction().equalsIgnoreCase("nvl")) { Type[] childTypes = collectChildReturnTypes(); - Type assignmentCompatibleType = ScalarType.getAssignmentCompatibleType(childTypes[0], childTypes[1], true); + Type assignmentCompatibleType = ScalarType.getAssignmentCompatibleType(childTypes[0], childTypes[1], true, + enableDecimal256); if (assignmentCompatibleType != Type.INVALID) { if (assignmentCompatibleType.isDecimalV3()) { if (assignmentCompatibleType.isDecimalV3() && !childTypes[0].equals(assignmentCompatibleType)) { @@ -1548,7 +1555,7 @@ public void analyzeImpl(Analyzer analyzer) throws AnalysisException { Type assignmentCompatibleType = childTypes[0]; for (int i = 1; i < childTypes.length; i++) { assignmentCompatibleType = ScalarType - .getAssignmentCompatibleType(assignmentCompatibleType, childTypes[i], true); + .getAssignmentCompatibleType(assignmentCompatibleType, childTypes[i], true, enableDecimal256); } if (assignmentCompatibleType.isDecimalV3()) { for (int i = 0; i < childTypes.length; i++) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/LargeIntLiteral.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/LargeIntLiteral.java index 9d191797048cdc..c284b963d52a98 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/LargeIntLiteral.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/LargeIntLiteral.java @@ -143,24 +143,30 @@ public Object getRealValue() { // little endian for hash code @Override public ByteBuffer getHashValue(PrimitiveType type) { - ByteBuffer buffer = ByteBuffer.allocate(16); + int buffLen = 0; + if (type == PrimitiveType.DECIMAL256) { + buffLen = 32; + } else { + buffLen = 16; + } + ByteBuffer buffer = ByteBuffer.allocate(buffLen); buffer.order(ByteOrder.LITTLE_ENDIAN); byte[] byteArray = value.toByteArray(); int len = byteArray.length; int end = 0; - if (len > 16) { - end = len - 16; + if (len > buffLen) { + end = len - buffLen; } for (int i = len - 1; i >= end; --i) { buffer.put(byteArray[i]); } if (value.signum() >= 0) { - while (len++ < 16) { + while (len++ < buffLen) { buffer.put((byte) 0); } } else { - while (len++ < 16) { + while (len++ < buffLen) { buffer.put((byte) 0xFF); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/MapLiteral.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/MapLiteral.java index ba9878977c3026..ead27d9e985e15 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/MapLiteral.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/MapLiteral.java @@ -20,6 +20,7 @@ import org.apache.doris.catalog.MapType; import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; +import org.apache.doris.qe.SessionVariable; import org.apache.doris.thrift.TExprNode; import org.apache.doris.thrift.TExprNodeType; import org.apache.doris.thrift.TTypeDesc; @@ -65,8 +66,9 @@ public MapLiteral(LiteralExpr... exprs) throws AnalysisException { if (!MapType.MAP.supportSubType(exprs[idx].getType())) { throw new AnalysisException("Invalid key type in Map, not support " + exprs[idx].getType()); } - keyType = Type.getAssignmentCompatibleType(keyType, exprs[idx].getType(), true); - valueType = Type.getAssignmentCompatibleType(valueType, exprs[idx + 1].getType(), true); + boolean enableDecimal256 = SessionVariable.getEnableDecimal256(); + keyType = Type.getAssignmentCompatibleType(keyType, exprs[idx].getType(), true, enableDecimal256); + valueType = Type.getAssignmentCompatibleType(valueType, exprs[idx + 1].getType(), true, enableDecimal256); } if (keyType == Type.INVALID) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/TypeDef.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/TypeDef.java index 431e10ce2eda4c..c7199b82b289b1 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/TypeDef.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/TypeDef.java @@ -29,7 +29,6 @@ import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.Config; -import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.SessionVariable; import org.apache.doris.thrift.TColumnDesc; import org.apache.doris.thrift.TPrimitiveType; @@ -304,15 +303,7 @@ private void analyzeScalarType(ScalarType scalarType) break; } case DECIMAL256: { - boolean enableNereidsPlanner = false; - boolean enableDecimal256 = false; - ConnectContext connectContext = ConnectContext.get(); - if (connectContext != null) { - SessionVariable sessionVariable = connectContext.getSessionVariable(); - enableDecimal256 = sessionVariable.enableDecimal256(); - enableNereidsPlanner = sessionVariable.isEnableNereidsPlanner(); - } - if (enableNereidsPlanner && enableDecimal256) { + if (SessionVariable.getEnableDecimal256()) { int precision = scalarType.decimalPrecision(); int scale = scalarType.decimalScale(); if (precision < 1 || precision > ScalarType.MAX_DECIMAL256_PRECISION) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java index 17d47bc4e33a25..2ee5485d7f8055 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Function.java @@ -28,6 +28,7 @@ import org.apache.doris.common.io.Text; import org.apache.doris.common.io.Writable; import org.apache.doris.common.util.URI; +import org.apache.doris.qe.SessionVariable; import org.apache.doris.thrift.TFunction; import org.apache.doris.thrift.TFunctionBinaryType; @@ -361,14 +362,16 @@ private boolean isSubtype(Function other) { return false; } for (int i = 0; i < this.argTypes.length; ++i) { - if (!Type.isImplicitlyCastable(other.argTypes[i], this.argTypes[i], true)) { + if (!Type.isImplicitlyCastable(other.argTypes[i], this.argTypes[i], true, + SessionVariable.getEnableDecimal256())) { return false; } } // Check trailing varargs. if (this.hasVarArgs) { for (int i = this.argTypes.length; i < other.argTypes.length; ++i) { - if (!Type.isImplicitlyCastable(other.argTypes[i], getVarArgsType(), true)) { + if (!Type.isImplicitlyCastable(other.argTypes[i], getVarArgsType(), true, + SessionVariable.getEnableDecimal256())) { return false; } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java index 665e7b75b4b5fa..f22a6eeed99349 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/FunctionSet.java @@ -29,6 +29,7 @@ import org.apache.doris.builtins.ScalarBuiltins; import org.apache.doris.catalog.Function.NullableMode; import org.apache.doris.qe.ConnectContext; +import org.apache.doris.qe.SessionVariable; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; @@ -387,17 +388,19 @@ public Function specializeTemplateFunction(Function templateFunction, Function r } Type[] args = specializedFunction.getArgs(); Map specializedTypeMap = Maps.newHashMap(); + boolean enableDecimal256 = SessionVariable.getEnableDecimal256(); for (int i = 0; i < args.length; i++) { if (args[i].hasTemplateType()) { hasTemplateType = true; - args[i] = args[i].specializeTemplateType(requestFunction.getArgs()[i], specializedTypeMap, false); + args[i] = args[i].specializeTemplateType(requestFunction.getArgs()[i], specializedTypeMap, false, + enableDecimal256); } } if (specializedFunction.getReturnType().hasTemplateType()) { hasTemplateType = true; specializedFunction.setReturnType( specializedFunction.getReturnType().specializeTemplateType( - requestFunction.getReturnType(), specializedTypeMap, true)); + requestFunction.getReturnType(), specializedTypeMap, true, enableDecimal256)); } if (LOG.isDebugEnabled()) { LOG.debug("specializedFunction signature: {}, return type: {}", diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionKey.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionKey.java index bf69a209e9ec48..eee87f3d6b798b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionKey.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/PartitionKey.java @@ -29,6 +29,7 @@ import org.apache.doris.common.io.Text; import org.apache.doris.common.io.Writable; import org.apache.doris.datasource.hive.HiveMetaStoreCache; +import org.apache.doris.qe.SessionVariable; import com.google.common.base.Joiner; import com.google.common.base.Preconditions; @@ -221,7 +222,9 @@ public static int compareLiteralExpr(LiteralExpr key1, LiteralExpr key2) { if (key1 instanceof MaxLiteral || key2 instanceof MaxLiteral) { ret = key1.compareLiteral(key2); } else { - final Type destType = Type.getAssignmentCompatibleType(key1.getType(), key2.getType(), false); + boolean enableDecimal256 = SessionVariable.getEnableDecimal256(); + final Type destType = Type.getAssignmentCompatibleType(key1.getType(), key2.getType(), false, + enableDecimal256); try { LiteralExpr newKey = key1; if (key1.getType() != destType) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Multiply.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Multiply.java index c420e061a574a3..52c43fa85612a9 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Multiply.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Multiply.java @@ -56,7 +56,7 @@ public DecimalV3Type getDataTypeForDecimalV3(DecimalV3Type t1, DecimalV3Type t2) boolean enableDecimal256 = false; ConnectContext connectContext = ConnectContext.get(); if (connectContext != null) { - enableDecimal256 = connectContext.getSessionVariable().enableDecimal256(); + enableDecimal256 = connectContext.getSessionVariable().isEnableDecimal256(); } if (enableDecimal256) { if (retPercision > DecimalV3Type.MAX_DECIMAL256_PRECISION) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputePrecisionForSum.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputePrecisionForSum.java index d78567e1652e59..36150af9923ebb 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputePrecisionForSum.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ComputePrecisionForSum.java @@ -32,7 +32,7 @@ default FunctionSignature computePrecision(FunctionSignature signature) { boolean enableDecimal256 = false; ConnectContext connectContext = ConnectContext.get(); if (connectContext != null) { - enableDecimal256 = connectContext.getSessionVariable().enableDecimal256(); + enableDecimal256 = connectContext.getSessionVariable().isEnableDecimal256(); } return signature.withArgumentType(0, decimalV3Type) .withReturnType(DecimalV3Type.createDecimalV3Type( diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ImplicitlyCastableSignature.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ImplicitlyCastableSignature.java index 490d1344b237af..eb3c4c03f18d8f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ImplicitlyCastableSignature.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/ImplicitlyCastableSignature.java @@ -24,6 +24,7 @@ import org.apache.doris.nereids.types.NullType; import org.apache.doris.nereids.types.coercion.AnyDataType; import org.apache.doris.nereids.types.coercion.FollowToAnyDataType; +import org.apache.doris.qe.SessionVariable; import java.util.List; @@ -58,7 +59,8 @@ static boolean isPrimitiveImplicitlyCastable(DataType signatureType, DataType re return false; } } - if (Type.isImplicitlyCastable(realType.toCatalogDataType(), signatureType.toCatalogDataType(), true)) { + if (Type.isImplicitlyCastable(realType.toCatalogDataType(), signatureType.toCatalogDataType(), true, + SessionVariable.getEnableDecimal256())) { return true; } } catch (Throwable t) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Avg.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Avg.java index 95863484862611..db1d8d7eb7c469 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Avg.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/agg/Avg.java @@ -92,7 +92,7 @@ public FunctionSignature computePrecision(FunctionSignature signature) { boolean enableDecimal256 = false; ConnectContext connectContext = ConnectContext.get(); if (connectContext != null) { - enableDecimal256 = connectContext.getSessionVariable().enableDecimal256(); + enableDecimal256 = connectContext.getSessionVariable().isEnableDecimal256(); } DecimalV3Type decimalV3Type = DecimalV3Type.forType(argumentType); // DecimalV3 scale lower than DEFAULT_MIN_AVG_DECIMAL128_SCALE should do cast diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java index 71c1f08745d9a4..9a5900908ce6e4 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/logical/LogicalSetOperation.java @@ -37,6 +37,7 @@ import org.apache.doris.nereids.types.StructField; import org.apache.doris.nereids.types.StructType; import org.apache.doris.nereids.util.TypeCoercionUtils; +import org.apache.doris.qe.SessionVariable; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; @@ -253,6 +254,7 @@ private DataType getAssignmentCompatibleType(DataType left, DataType right) { return DataType.fromCatalogType(Type.getAssignmentCompatibleType( left.toCatalogDataType(), right.toCatalogDataType(), - false)); + false, + SessionVariable.getEnableDecimal256())); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DecimalV3Type.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DecimalV3Type.java index 6d1e43383bb0a9..f87f95db4a3b0f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DecimalV3Type.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/DecimalV3Type.java @@ -110,7 +110,7 @@ public static DecimalV3Type createDecimalV3Type(int precision, int scale) { boolean enableDecimal256 = false; ConnectContext connectContext = ConnectContext.get(); if (connectContext != null) { - enableDecimal256 = connectContext.getSessionVariable().enableDecimal256(); + enableDecimal256 = connectContext.getSessionVariable().isEnableDecimal256(); } if (precision > MAX_DECIMAL128_PRECISION && !enableDecimal256) { throw new NotSupportedException("Datatype DecimalV3 with precision " + precision @@ -133,7 +133,7 @@ public static DecimalV3Type createDecimalV3TypeLooseCheck(int precision, int sca boolean enableDecimal256 = false; ConnectContext connectContext = ConnectContext.get(); if (connectContext != null) { - enableDecimal256 = connectContext.getSessionVariable().enableDecimal256(); + enableDecimal256 = connectContext.getSessionVariable().isEnableDecimal256(); } if (enableDecimal256) { Preconditions.checkArgument(precision > 0 && precision <= MAX_DECIMAL256_PRECISION, @@ -169,7 +169,7 @@ private static DataType widerDecimalV3Type( boolean enableDecimal256 = false; ConnectContext connectContext = ConnectContext.get(); if (connectContext != null) { - enableDecimal256 = connectContext.getSessionVariable().enableDecimal256(); + enableDecimal256 = connectContext.getSessionVariable().isEnableDecimal256(); } if (range + scale > (enableDecimal256 ? MAX_DECIMAL256_PRECISION : MAX_DECIMAL128_PRECISION) && overflowToDouble) { @@ -247,7 +247,7 @@ public int width() { boolean enableDecimal256 = false; ConnectContext connectContext = ConnectContext.get(); if (connectContext != null) { - enableDecimal256 = connectContext.getSessionVariable().enableDecimal256(); + enableDecimal256 = connectContext.getSessionVariable().isEnableDecimal256(); } if (enableDecimal256) { return 32; diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java index 9cb2b5edc84e56..369805700399ab 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java @@ -2840,7 +2840,16 @@ public static boolean enableAggState() { return connectContext.getSessionVariable().enableAggState; } - public boolean enableDecimal256() { + public static boolean getEnableDecimal256() { + ConnectContext connectContext = ConnectContext.get(); + if (connectContext == null) { + return false; + } + SessionVariable sessionVariable = connectContext.getSessionVariable(); + return sessionVariable.isEnableNereidsPlanner() && sessionVariable.isEnableDecimal256(); + } + + public boolean isEnableDecimal256() { return enableDecimal256; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java index d7bfd826557e34..86429f09e24cf0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/util/StatisticsUtil.java @@ -228,6 +228,7 @@ public static LiteralExpr readableValue(Type type, String columnValue) throws An case DECIMAL32: case DECIMAL64: case DECIMAL128: + case DECIMAL256: DecimalLiteral decimalLiteral = new DecimalLiteral(columnValue); decimalLiteral.checkPrecisionAndScale(scalarType.getScalarPrecision(), scalarType.getScalarScale()); return decimalLiteral; @@ -273,6 +274,7 @@ public static double convertToDouble(Type type, String columnValue) throws Analy case DECIMAL32: case DECIMAL64: case DECIMAL128: + case DECIMAL256: return Double.parseDouble(columnValue); case DATE: case DATEV2: diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/GenerateFunction.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/GenerateFunction.java index 038efc76e9d9d2..514062b67928d7 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/GenerateFunction.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/rules/analysis/GenerateFunction.java @@ -1398,7 +1398,7 @@ public String fields() { + " Type assignmentCompatibleType = ScalarType.getAssignmentCompatibleType(\n" + " getArgumentType(1).toCatalogDataType(),\n" + " getArgumentType(2).toCatalogDataType(),\n" - + " true);\n" + + " true, false);\n" + " return DataType.fromCatalogType(assignmentCompatibleType);\n" + " });\n" + "\n"; diff --git a/regression-test/data/datatype_p0/decimalv3/test_arithmetic_expressions.out b/regression-test/data/datatype_p0/decimalv3/test_arithmetic_expressions.out index 72db6bf6f27ac0..9361d86f2cb9a8 100644 --- a/regression-test/data/datatype_p0/decimalv3/test_arithmetic_expressions.out +++ b/regression-test/data/datatype_p0/decimalv3/test_arithmetic_expressions.out @@ -65,9 +65,101 @@ 3.000000 33333333333333333333333333333333.333333 33333333333333333333333333333333.333333 4.444444 2.222222 3.333333 +-- !decimal128_multiply_0 -- +9.876541234568 +99999999999999999999999999.999999999999 +99999999999999999999999999.999999999999 +99999999999999999999999999.999999999999 + +-- !decimal128_arith_union -- +3.333333000000 +9.876541234568 +99999999999999999999999999.999999999999 +99999999999999999999999999.999999999999 +99999999999999999999999999.999999999999 +33333333333333333333333333333333.333333000000 +49999999999999999999999999999999.999999000000 +99999999999999999999999999999999.999999000000 + +-- !decimal128_multiply_1 -- +32.921800823046255144 +99999999999999999999.999999999999999999 +99999999999999999999.999999999999999999 +99999999999999999999.999999999999999999 + +-- !decimal128_multiply_2 -- +99.999999999999999999999999999999999999 +99.999999999999999999999999999999999999 +99.999999999999999999999999999999999999 +99.999999999999999999999999999999999999 + +-- !decimal128_multiply_div -- +1.0000000000000001E58 +1.0000000000000001E58 +1.0E58 +97.54606675812198 + -- !decimal128_select_all_2 -- 999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 +-- !decimal128_mixed_calc_0 -- +2999999.997 + +-- !decimal128_mixed_calc_1 -- +2.999999994E12 + +-- !decimal128_mixed_calc_2 -- +3.0 + +-- !decimal128_mixed_calc_3 -- +1.0999999989E7 + +-- !decimal128_enable_decimal256_multiply_0 -- +9.876541234568 +99999999999999999999999999999999.999998000000 +99999999999999999999999999999999.999999000000 +99999999999999999999999999999999.999999000000 + +-- !decimal128_enable_decimal256_arith_union -- +3.333333000000 +9.876541234568 +33333333333333333333333333333333.333333000000 +49999999999999999999999999999999.999999000000 +99999999999999999999999999999999.999998000000 +99999999999999999999999999999999.999999000000 +99999999999999999999999999999999.999999000000 +99999999999999999999999999999999.999999000000 + +-- !decimal128_enable_decimal256_multiply_1 -- +32.921800823046255144 +9999999999999999999999999999999999999999999999999999999999.999999999999999999 +9999999999999999999999999999999999999999999999999999999999.999999999999999999 +9999999999999999999999999999999999999999999999999999999999.999999999999999999 + +-- !decimal128_enable_decimal256_multiply_2 -- +9999999999999999999999999999999999999999.999999999999999999999999999999999999 +9999999999999999999999999999999999999999.999999999999999999999999999999999999 +9999999999999999999999999999999999999999.999999999999999999999999999999999999 +1083.844969432329082604616506562346460736 + +-- !decimal128_enable_decimal256_multiply_div -- +1.0000000000000002E64 +1.0000000000000002E64 +1.0E64 +97.54606675812198 + +-- !decimal128_enable_decimal256_mixed_calc_0 -- +2999999.997 + +-- !decimal128_enable_decimal256_mixed_calc_1 -- +2999999994000.000003 + +-- !decimal128_enable_decimal256_mixed_calc_2 -- +3.0000000 + +-- !decimal128_enable_decimal256_mixed_calc_3 -- +10999999.989 + -- !decimal128_cast256_cast -- 3.333333 3.3333330000 33333333333333333333333333333333.333333 33333333333333333333333333333333.3333330000 @@ -150,3 +242,88 @@ -- !decimal128_cast256_mixed_calc_7 -- 1.0999999989E7 +-- !decimal256_arith_select_all -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !decimal256_arith_plus -- +3.3333333333333333E65 +5.000000000000001E65 +1.0000000000000001E66 + +-- !decimal256_arith_minus -- +3.3333333333333333E65 +5.000000000000001E65 +1.0000000000000001E66 + +-- !decimal256_arith_multiply -- +999999999999999999999999999999999999999999999999999999999.9999999999999999999 +999999999999999999999999999999999999999999999999999999999.9999999999999999999 +999999999999999999999999999999999999999999999999999999999.9999999999999999999 + +-- !decimal256_arith_div -- +1.111111111111111E65 +2.5000000000000003E65 +1.0000000000000001E66 + +-- !decimal256_arith_union -- +-999999999999999999999999999999999999999999999999999999999.9999999999999999999 +-999999999999999999999999999999999999999999999999999999999.9999999999999999999 +999999999999999999999999999999999999999999999999999999999.9999999999999999999 +999999999999999999999999999999999999999999999999999999999.9999999999999999999 +999999999999999999999999999999999999999999999999999999999.9999999999999999999 +999999999999999999999999999999999999999999999999999999999.9999999999999999999 + +-- !decimal256_multiply_1 -- +9999999999999999999999999999999999999999999999.999999999999999999999999999999 +9999999999999999999999999999999999999999999999.999999999999999999999999999999 +9999999999999999999999999999999999999999999999.999999999999999999999999999999 + +-- !decimal256_multiply_2 -- +9999999999999999.999999999999999999999999999999999999999999999999999999999999 +9999999999999999.999999999999999999999999999999999999999999999999999999999999 +9999999999999999.999999999999999999999999999999999999999999999999999999999999 + +-- !decimal256_multiply_div -- +1.0000000000000003E123 +1.0000000000000003E123 +1.0000000000000001E123 + +-- !decimal256_arith_multiply_const -- +2.0000000000 +4.0000000000 +6.0000000000 + +-- !decimal256_select_all_2 -- +999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 999999.999 + +-- !decimal256_mixed_calc_0 -- +2999999.997 + +-- !decimal256_mixed_calc_1 -- +2.999999994E12 + +-- !decimal256_mixed_calc_2 -- +3.0 + +-- !decimal256_mixed_calc_3 -- +1.0999999989E7 + +-- !decimal256_arith_3 -- +1 999999999999999999999999999999999999999999999999999999999999999999999999999.9 999999999999999999999999999999999999999999999999999999999999999999999999999.9 +2 499999999999999999999999999999999999999999999999999999999999999999999999999.9 999999999999999999999999999999999999999999999999999999999999999999999999999.8 +3 333333333333333333333333333333333333333333333333333333333333333333333333333.3 999999999999999999999999999999999999999999999999999999999999999999999999999.9 + +-- !decimal256_div_v2_v3 -- +1 629.0287029333568 629.028702933357 +2 722.8102124296118 722.8102124296119 +3 724.2919760003956 724.2919760003956 +4 688.8901831550861 688.8901831550862 + +-- !decimal256_mod -- +92594283.129196000 1 0.129196000 0.129196000 +107684988.257976000 3 0.257976000 0.257976000 +76891560.464178000 5 0.464178000 0.464178000 +277170831.851350000 7 0.851350000 0.851350000 + diff --git a/regression-test/data/datatype_p0/decimalv3/test_decimal256_cast.out b/regression-test/data/datatype_p0/decimalv3/test_decimal256_cast.out new file mode 100644 index 00000000000000..28cd6f12839d6d --- /dev/null +++ b/regression-test/data/datatype_p0/decimalv3/test_decimal256_cast.out @@ -0,0 +1,25 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !decimal256_cast0 -- +999999999999999999999999999999999999999999999999999999999999999999.9999999999 + +-- !decimal256_cast1 -- +-999999999999999999999999999999999999999999999999999999999999999999.9999999999 + +-- !decimal256_cast2 -- +999999999999999999999999999999999999999999999999999999999999999999.9999999999 + +-- !decimal256_cast3 -- +-999999999999999999999999999999999999999999999999999999999999999999.9999999999 + +-- !decimal256_cast4 -- +999999999999999999999999999999999999999999999999999999999999999999.9999999999 + +-- !decimal256_cast5 -- +-999999999999999999999999999999999999999999999999999999999999999999.9999999999 + +-- !decimal256_cast6 -- +999999999999999999999999999999999999999999999999999999999999999999.9999999999 + +-- !decimal256_cast7 -- +-999999999999999999999999999999999999999999999999999999999999999999.9999999999 + diff --git a/regression-test/data/datatype_p0/decimalv3/test_decimal256_index.out b/regression-test/data/datatype_p0/decimalv3/test_decimal256_index.out new file mode 100644 index 00000000000000..6a961a69931dd4 --- /dev/null +++ b/regression-test/data/datatype_p0/decimalv3/test_decimal256_index.out @@ -0,0 +1,259 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !decimal256_zonemap_0 -- +1.000000000 900000000000000000000000000000000000000000000000000000000000000001.9999999999 +2.000000000 900000000000000000000000000000000000000000000000000000000000000002.9999999999 +3.000000000 900000000000000000000000000000000000000000000000000000000000000003.9999999999 +4.000000000 900000000000000000000000000000000000000000000000000000000000000004.9999999999 +5.000000000 900000000000000000000000000000000000000000000000000000000000000005.9999999999 +6.000000000 900000000000000000000000000000000000000000000000000000000000000006.9999999999 +7.000000000 900000000000000000000000000000000000000000000000000000000000000007.9999999999 +8.000000000 900000000000000000000000000000000000000000000000000000000000000008.9999999999 +9.000000000 900000000000000000000000000000000000000000000000000000000000000009.9999999999 + +-- !sql_bitmap_index_select_all -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_eq_1 -- +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_eq_2 -- +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_eq_3 -- +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_neq_1 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_neq_2 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_neq_3 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_gt_1 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_gt_2 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_gt_3 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_ge_1 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_ge_2 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_ge_3 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_lt_1 -- +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_lt_2 -- + +-- !sql_lt_3 -- +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_le_1 -- +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_le_2 -- +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_le_3 -- +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_bf_eq_1 -- +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_bf_eq_2 -- +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_bf_eq_3 -- +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_bf_neq_1 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_bf_neq_2 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_bf_neq_3 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_bf_gt_1 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_bf_gt_2 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_bf_gt_3 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_bf_ge_1 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_bf_ge_2 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_bf_ge_3 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_bf_lt_1 -- +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_bf_lt_2 -- + +-- !sql_bf_lt_3 -- +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_bf_le_1 -- +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !sql_bf_le_2 -- +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_bf_le_3 -- +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + diff --git a/regression-test/data/datatype_p0/decimalv3/test_decimal256_load.csv b/regression-test/data/datatype_p0/decimalv3/test_decimal256_load.csv new file mode 100644 index 00000000000000..65a862f15009e8 --- /dev/null +++ b/regression-test/data/datatype_p0/decimalv3/test_decimal256_load.csv @@ -0,0 +1,19 @@ +2, 499999999999999999999999999999999999999999999999999999999999999999.9999999999, 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4, -999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +3, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4, -999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +3, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5, -333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5, -333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6, null, 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7, null, 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +0, 0, 0 +99999999999999999999999999999.999999999, 1, 1 +-99999999999999999999999999999.999999999, 1, 1 +9999999999999999999999999999999999999999999999999999999999999999999.999999999, 1, 1 +-9999999999999999999999999999999999999999999999999999999999999999999.999999999, 1, 1 +4999999999999999999999999999999999999999999999999999999999999999999.999999999, 1, 1 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999, 1, 1 +null, null, null \ No newline at end of file diff --git a/regression-test/data/datatype_p0/decimalv3/test_decimal256_load.out b/regression-test/data/datatype_p0/decimalv3/test_decimal256_load.out new file mode 100644 index 00000000000000..dcfa3fb0233c23 --- /dev/null +++ b/regression-test/data/datatype_p0/decimalv3/test_decimal256_load.out @@ -0,0 +1,664 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !decimal256_insert_select_all0 -- +\N \N \N +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select -- +\N \N \N +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_eq0 -- +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_eq1 -- +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_eq2 -- +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_eq3 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_eq4 -- +0E-9 0E-10 0E-11 + +-- !select_key_eq5 -- + +-- !select_key_neq0 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_neq1 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_neq2 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_neq3 -- +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_neq4 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_neq5 -- + +-- !select_key_gt0 -- + +-- !select_key_gt1 -- +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_gt2 -- +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_gt3 -- +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_gt4 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_gt5 -- + +-- !select_key_ge0 -- +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_ge1 -- +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_ge2 -- +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_ge3 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_ge4 -- +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_ge5 -- + +-- !select_key_lt0 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_lt1 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_lt2 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_lt3 -- + +-- !select_key_lt4 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_lt5 -- + +-- !select_key_le0 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_le1 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_le2 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_le3 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_le4 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 + +-- !select_key_le5 -- + +-- !select_key_in0 -- +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_in1 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_in2 -- +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_in3 -- +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_in4 -- +0E-9 0E-10 0E-11 + +-- !select_key_in5 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_in6 -- + +-- !select_key_in7 -- +0E-9 0E-10 0E-11 + +-- !select_key_notin0 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_notin1 -- +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_notin2 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_notin3 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_notin4 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_notin5 -- +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_key_notin6 -- + +-- !select_key_notin7 -- + +-- !select_key_is_null -- +\N \N \N + +-- !select_key_is_not_null -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !sql_eq_1 -- +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_neq_1 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !sql_gt_1 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_ge_1 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_lt_1 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !sql_le_1 -- +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !select_2 -- +\N \N \N +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !sql_insert_select_eq_1 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !sql_select_insert_default0 -- +\N \N \N +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 -99999.00000000000 +0E-9 0E-10 0E-11 +0E-9 999999999999999999999999999999999999999999999999999999999999999999.9999999999 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999.00000000000 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + +-- !sql_select_insert_default1 -- +99999.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999.00000000000 + +-- !sql_select_insert_default2 -- +-99999.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 -99999.00000000000 + diff --git a/regression-test/data/datatype_p0/decimalv3/test_decimal256_outfile_csv.out b/regression-test/data/datatype_p0/decimalv3/test_decimal256_outfile_csv.out new file mode 100644 index 00000000000000..6dd74d5daa541a --- /dev/null +++ b/regression-test/data/datatype_p0/decimalv3/test_decimal256_outfile_csv.out @@ -0,0 +1,22 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !sql_select_all -- +\N \N \N +-9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +-99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +0E-9 0E-10 0E-11 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +99999999999999999999999999999.999999999 1.0000000000 1.00000000000 +4999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 +9999999999999999999999999999999999999999999999999999999999999999999.999999999 1.0000000000 1.00000000000 + diff --git a/regression-test/data/datatype_p0/decimalv3/test_decimal256_predicate.out b/regression-test/data/datatype_p0/decimalv3/test_decimal256_predicate.out new file mode 100644 index 00000000000000..16961bb57a5948 --- /dev/null +++ b/regression-test/data/datatype_p0/decimalv3/test_decimal256_predicate.out @@ -0,0 +1,178 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select256_1 -- +true + +-- !select256_2 -- +false + +-- !select256_3 -- +true + +-- !select256_4 -- +false + +-- !select256_5 -- +true + +-- !select256_6 -- +false + +-- !select256_7 -- +true + +-- !select256_8 -- +false + +-- !select256_9 -- +true + +-- !select256_10 -- +false + +-- !select256_11 -- +true + +-- !select256_12 -- +false + +-- !select256_fold_const_by_be1 -- +true + +-- !select256_fold_const_by_be2 -- +false + +-- !select256_fold_const_by_be3 -- +true + +-- !select256_fold_const_by_be4 -- +false + +-- !select256_fold_const_by_be5 -- +true + +-- !select256_fold_const_by_be6 -- +false + +-- !select256_fold_const_by_be7 -- +true + +-- !select256_fold_const_by_be8 -- +false + +-- !select256_fold_const_by_be9 -- +true + +-- !select256_fold_const_by_be10 -- +false + +-- !select256_fold_const_by_be11 -- +true + +-- !select256_fold_const_by_be12 -- +false + +-- !decimal256_select_all -- +1.000000 99999999999999999999999999999999.999999 99999999999999999999999999999999.999999 +2.000000 49999999999999999999999999999999.999999 49999999999999999999999999999999.999999 +3.000000 33333333333333333333333333333333.333333 33333333333333333333333333333333.333333 +4.444444 2.222222 3.333333 + +-- !decimal256_predicate_0 -- +1.000000 99999999999999999999999999999999.999999 99999999999999999999999999999999.999999 +2.000000 49999999999999999999999999999999.999999 49999999999999999999999999999999.999999 + +-- !decimal256_predicate_1 -- +1.000000 99999999999999999999999999999999.999999 99999999999999999999999999999999.999999 + +-- !decimal256_predicate_2 -- +3.000000 33333333333333333333333333333333.333333 33333333333333333333333333333333.333333 +4.444444 2.222222 3.333333 + +-- !decimal256_predicate_3 -- +3.000000 33333333333333333333333333333333.333333 33333333333333333333333333333333.333333 +4.444444 2.222222 3.333333 + +-- !decimal256_predicate_4 -- +1.000000 99999999999999999999999999999999.999999 99999999999999999999999999999999.999999 + +-- !decimal256_predicate_5 -- +2.000000 49999999999999999999999999999999.999999 49999999999999999999999999999999.999999 +3.000000 33333333333333333333333333333333.333333 33333333333333333333333333333333.333333 +4.444444 2.222222 3.333333 + +-- !decimal256_select_all2 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !decimal256_predicate_6 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !decimal256_predicate_7 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !decimal256_predicate_8 -- +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !decimal256_predicate_9 -- +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !decimal256_predicate_10 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !decimal256_predicate_11 -- +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !decimal256_predicate_12 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !decimal256_predicate_13 -- +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !decimal256_predicate_14 -- +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +4.000000000 -999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +5.000000000 -333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 +6.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +7.000000000 \N 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + diff --git a/regression-test/data/datatype_p0/decimalv3/test_decimal256_zonemap_index.csv b/regression-test/data/datatype_p0/decimalv3/test_decimal256_zonemap_index.csv new file mode 100644 index 00000000000000..f09b11131f04d1 --- /dev/null +++ b/regression-test/data/datatype_p0/decimalv3/test_decimal256_zonemap_index.csv @@ -0,0 +1,4096 @@ +1,900000000000000000000000000000000000000000000000000000000000000001.9999999999 +2,900000000000000000000000000000000000000000000000000000000000000002.9999999999 +3,900000000000000000000000000000000000000000000000000000000000000003.9999999999 +4,900000000000000000000000000000000000000000000000000000000000000004.9999999999 +5,900000000000000000000000000000000000000000000000000000000000000005.9999999999 +6,900000000000000000000000000000000000000000000000000000000000000006.9999999999 +7,900000000000000000000000000000000000000000000000000000000000000007.9999999999 +8,900000000000000000000000000000000000000000000000000000000000000008.9999999999 +9,900000000000000000000000000000000000000000000000000000000000000009.9999999999 +10,900000000000000000000000000000000000000000000000000000000000000010.9999999999 +11,900000000000000000000000000000000000000000000000000000000000000011.9999999999 +12,900000000000000000000000000000000000000000000000000000000000000012.9999999999 +13,900000000000000000000000000000000000000000000000000000000000000013.9999999999 +14,900000000000000000000000000000000000000000000000000000000000000014.9999999999 +15,900000000000000000000000000000000000000000000000000000000000000015.9999999999 +16,900000000000000000000000000000000000000000000000000000000000000016.9999999999 +17,900000000000000000000000000000000000000000000000000000000000000017.9999999999 +18,900000000000000000000000000000000000000000000000000000000000000018.9999999999 +19,900000000000000000000000000000000000000000000000000000000000000019.9999999999 +20,900000000000000000000000000000000000000000000000000000000000000020.9999999999 +21,900000000000000000000000000000000000000000000000000000000000000021.9999999999 +22,900000000000000000000000000000000000000000000000000000000000000022.9999999999 +23,900000000000000000000000000000000000000000000000000000000000000023.9999999999 +24,900000000000000000000000000000000000000000000000000000000000000024.9999999999 +25,900000000000000000000000000000000000000000000000000000000000000025.9999999999 +26,900000000000000000000000000000000000000000000000000000000000000026.9999999999 +27,900000000000000000000000000000000000000000000000000000000000000027.9999999999 +28,900000000000000000000000000000000000000000000000000000000000000028.9999999999 +29,900000000000000000000000000000000000000000000000000000000000000029.9999999999 +30,900000000000000000000000000000000000000000000000000000000000000030.9999999999 +31,900000000000000000000000000000000000000000000000000000000000000031.9999999999 +32,900000000000000000000000000000000000000000000000000000000000000032.9999999999 +33,900000000000000000000000000000000000000000000000000000000000000033.9999999999 +34,900000000000000000000000000000000000000000000000000000000000000034.9999999999 +35,900000000000000000000000000000000000000000000000000000000000000035.9999999999 +36,900000000000000000000000000000000000000000000000000000000000000036.9999999999 +37,900000000000000000000000000000000000000000000000000000000000000037.9999999999 +38,900000000000000000000000000000000000000000000000000000000000000038.9999999999 +39,900000000000000000000000000000000000000000000000000000000000000039.9999999999 +40,900000000000000000000000000000000000000000000000000000000000000040.9999999999 +41,900000000000000000000000000000000000000000000000000000000000000041.9999999999 +42,900000000000000000000000000000000000000000000000000000000000000042.9999999999 +43,900000000000000000000000000000000000000000000000000000000000000043.9999999999 +44,900000000000000000000000000000000000000000000000000000000000000044.9999999999 +45,900000000000000000000000000000000000000000000000000000000000000045.9999999999 +46,900000000000000000000000000000000000000000000000000000000000000046.9999999999 +47,900000000000000000000000000000000000000000000000000000000000000047.9999999999 +48,900000000000000000000000000000000000000000000000000000000000000048.9999999999 +49,900000000000000000000000000000000000000000000000000000000000000049.9999999999 +50,900000000000000000000000000000000000000000000000000000000000000050.9999999999 +51,900000000000000000000000000000000000000000000000000000000000000051.9999999999 +52,900000000000000000000000000000000000000000000000000000000000000052.9999999999 +53,900000000000000000000000000000000000000000000000000000000000000053.9999999999 +54,900000000000000000000000000000000000000000000000000000000000000054.9999999999 +55,900000000000000000000000000000000000000000000000000000000000000055.9999999999 +56,900000000000000000000000000000000000000000000000000000000000000056.9999999999 +57,900000000000000000000000000000000000000000000000000000000000000057.9999999999 +58,900000000000000000000000000000000000000000000000000000000000000058.9999999999 +59,900000000000000000000000000000000000000000000000000000000000000059.9999999999 +60,900000000000000000000000000000000000000000000000000000000000000060.9999999999 +61,900000000000000000000000000000000000000000000000000000000000000061.9999999999 +62,900000000000000000000000000000000000000000000000000000000000000062.9999999999 +63,900000000000000000000000000000000000000000000000000000000000000063.9999999999 +64,900000000000000000000000000000000000000000000000000000000000000064.9999999999 +65,900000000000000000000000000000000000000000000000000000000000000065.9999999999 +66,900000000000000000000000000000000000000000000000000000000000000066.9999999999 +67,900000000000000000000000000000000000000000000000000000000000000067.9999999999 +68,900000000000000000000000000000000000000000000000000000000000000068.9999999999 +69,900000000000000000000000000000000000000000000000000000000000000069.9999999999 +70,900000000000000000000000000000000000000000000000000000000000000070.9999999999 +71,900000000000000000000000000000000000000000000000000000000000000071.9999999999 +72,900000000000000000000000000000000000000000000000000000000000000072.9999999999 +73,900000000000000000000000000000000000000000000000000000000000000073.9999999999 +74,900000000000000000000000000000000000000000000000000000000000000074.9999999999 +75,900000000000000000000000000000000000000000000000000000000000000075.9999999999 +76,900000000000000000000000000000000000000000000000000000000000000076.9999999999 +77,900000000000000000000000000000000000000000000000000000000000000077.9999999999 +78,900000000000000000000000000000000000000000000000000000000000000078.9999999999 +79,900000000000000000000000000000000000000000000000000000000000000079.9999999999 +80,900000000000000000000000000000000000000000000000000000000000000080.9999999999 +81,900000000000000000000000000000000000000000000000000000000000000081.9999999999 +82,900000000000000000000000000000000000000000000000000000000000000082.9999999999 +83,900000000000000000000000000000000000000000000000000000000000000083.9999999999 +84,900000000000000000000000000000000000000000000000000000000000000084.9999999999 +85,900000000000000000000000000000000000000000000000000000000000000085.9999999999 +86,900000000000000000000000000000000000000000000000000000000000000086.9999999999 +87,900000000000000000000000000000000000000000000000000000000000000087.9999999999 +88,900000000000000000000000000000000000000000000000000000000000000088.9999999999 +89,900000000000000000000000000000000000000000000000000000000000000089.9999999999 +90,900000000000000000000000000000000000000000000000000000000000000090.9999999999 +91,900000000000000000000000000000000000000000000000000000000000000091.9999999999 +92,900000000000000000000000000000000000000000000000000000000000000092.9999999999 +93,900000000000000000000000000000000000000000000000000000000000000093.9999999999 +94,900000000000000000000000000000000000000000000000000000000000000094.9999999999 +95,900000000000000000000000000000000000000000000000000000000000000095.9999999999 +96,900000000000000000000000000000000000000000000000000000000000000096.9999999999 +97,900000000000000000000000000000000000000000000000000000000000000097.9999999999 +98,900000000000000000000000000000000000000000000000000000000000000098.9999999999 +99,900000000000000000000000000000000000000000000000000000000000000099.9999999999 +100,900000000000000000000000000000000000000000000000000000000000000100.9999999999 +101,900000000000000000000000000000000000000000000000000000000000000101.9999999999 +102,900000000000000000000000000000000000000000000000000000000000000102.9999999999 +103,900000000000000000000000000000000000000000000000000000000000000103.9999999999 +104,900000000000000000000000000000000000000000000000000000000000000104.9999999999 +105,900000000000000000000000000000000000000000000000000000000000000105.9999999999 +106,900000000000000000000000000000000000000000000000000000000000000106.9999999999 +107,900000000000000000000000000000000000000000000000000000000000000107.9999999999 +108,900000000000000000000000000000000000000000000000000000000000000108.9999999999 +109,900000000000000000000000000000000000000000000000000000000000000109.9999999999 +110,900000000000000000000000000000000000000000000000000000000000000110.9999999999 +111,900000000000000000000000000000000000000000000000000000000000000111.9999999999 +112,900000000000000000000000000000000000000000000000000000000000000112.9999999999 +113,900000000000000000000000000000000000000000000000000000000000000113.9999999999 +114,900000000000000000000000000000000000000000000000000000000000000114.9999999999 +115,900000000000000000000000000000000000000000000000000000000000000115.9999999999 +116,900000000000000000000000000000000000000000000000000000000000000116.9999999999 +117,900000000000000000000000000000000000000000000000000000000000000117.9999999999 +118,900000000000000000000000000000000000000000000000000000000000000118.9999999999 +119,900000000000000000000000000000000000000000000000000000000000000119.9999999999 +120,900000000000000000000000000000000000000000000000000000000000000120.9999999999 +121,900000000000000000000000000000000000000000000000000000000000000121.9999999999 +122,900000000000000000000000000000000000000000000000000000000000000122.9999999999 +123,900000000000000000000000000000000000000000000000000000000000000123.9999999999 +124,900000000000000000000000000000000000000000000000000000000000000124.9999999999 +125,900000000000000000000000000000000000000000000000000000000000000125.9999999999 +126,900000000000000000000000000000000000000000000000000000000000000126.9999999999 +127,900000000000000000000000000000000000000000000000000000000000000127.9999999999 +128,900000000000000000000000000000000000000000000000000000000000000128.9999999999 +129,900000000000000000000000000000000000000000000000000000000000000129.9999999999 +130,900000000000000000000000000000000000000000000000000000000000000130.9999999999 +131,900000000000000000000000000000000000000000000000000000000000000131.9999999999 +132,900000000000000000000000000000000000000000000000000000000000000132.9999999999 +133,900000000000000000000000000000000000000000000000000000000000000133.9999999999 +134,900000000000000000000000000000000000000000000000000000000000000134.9999999999 +135,900000000000000000000000000000000000000000000000000000000000000135.9999999999 +136,900000000000000000000000000000000000000000000000000000000000000136.9999999999 +137,900000000000000000000000000000000000000000000000000000000000000137.9999999999 +138,900000000000000000000000000000000000000000000000000000000000000138.9999999999 +139,900000000000000000000000000000000000000000000000000000000000000139.9999999999 +140,900000000000000000000000000000000000000000000000000000000000000140.9999999999 +141,900000000000000000000000000000000000000000000000000000000000000141.9999999999 +142,900000000000000000000000000000000000000000000000000000000000000142.9999999999 +143,900000000000000000000000000000000000000000000000000000000000000143.9999999999 +144,900000000000000000000000000000000000000000000000000000000000000144.9999999999 +145,900000000000000000000000000000000000000000000000000000000000000145.9999999999 +146,900000000000000000000000000000000000000000000000000000000000000146.9999999999 +147,900000000000000000000000000000000000000000000000000000000000000147.9999999999 +148,900000000000000000000000000000000000000000000000000000000000000148.9999999999 +149,900000000000000000000000000000000000000000000000000000000000000149.9999999999 +150,900000000000000000000000000000000000000000000000000000000000000150.9999999999 +151,900000000000000000000000000000000000000000000000000000000000000151.9999999999 +152,900000000000000000000000000000000000000000000000000000000000000152.9999999999 +153,900000000000000000000000000000000000000000000000000000000000000153.9999999999 +154,900000000000000000000000000000000000000000000000000000000000000154.9999999999 +155,900000000000000000000000000000000000000000000000000000000000000155.9999999999 +156,900000000000000000000000000000000000000000000000000000000000000156.9999999999 +157,900000000000000000000000000000000000000000000000000000000000000157.9999999999 +158,900000000000000000000000000000000000000000000000000000000000000158.9999999999 +159,900000000000000000000000000000000000000000000000000000000000000159.9999999999 +160,900000000000000000000000000000000000000000000000000000000000000160.9999999999 +161,900000000000000000000000000000000000000000000000000000000000000161.9999999999 +162,900000000000000000000000000000000000000000000000000000000000000162.9999999999 +163,900000000000000000000000000000000000000000000000000000000000000163.9999999999 +164,900000000000000000000000000000000000000000000000000000000000000164.9999999999 +165,900000000000000000000000000000000000000000000000000000000000000165.9999999999 +166,900000000000000000000000000000000000000000000000000000000000000166.9999999999 +167,900000000000000000000000000000000000000000000000000000000000000167.9999999999 +168,900000000000000000000000000000000000000000000000000000000000000168.9999999999 +169,900000000000000000000000000000000000000000000000000000000000000169.9999999999 +170,900000000000000000000000000000000000000000000000000000000000000170.9999999999 +171,900000000000000000000000000000000000000000000000000000000000000171.9999999999 +172,900000000000000000000000000000000000000000000000000000000000000172.9999999999 +173,900000000000000000000000000000000000000000000000000000000000000173.9999999999 +174,900000000000000000000000000000000000000000000000000000000000000174.9999999999 +175,900000000000000000000000000000000000000000000000000000000000000175.9999999999 +176,900000000000000000000000000000000000000000000000000000000000000176.9999999999 +177,900000000000000000000000000000000000000000000000000000000000000177.9999999999 +178,900000000000000000000000000000000000000000000000000000000000000178.9999999999 +179,900000000000000000000000000000000000000000000000000000000000000179.9999999999 +180,900000000000000000000000000000000000000000000000000000000000000180.9999999999 +181,900000000000000000000000000000000000000000000000000000000000000181.9999999999 +182,900000000000000000000000000000000000000000000000000000000000000182.9999999999 +183,900000000000000000000000000000000000000000000000000000000000000183.9999999999 +184,900000000000000000000000000000000000000000000000000000000000000184.9999999999 +185,900000000000000000000000000000000000000000000000000000000000000185.9999999999 +186,900000000000000000000000000000000000000000000000000000000000000186.9999999999 +187,900000000000000000000000000000000000000000000000000000000000000187.9999999999 +188,900000000000000000000000000000000000000000000000000000000000000188.9999999999 +189,900000000000000000000000000000000000000000000000000000000000000189.9999999999 +190,900000000000000000000000000000000000000000000000000000000000000190.9999999999 +191,900000000000000000000000000000000000000000000000000000000000000191.9999999999 +192,900000000000000000000000000000000000000000000000000000000000000192.9999999999 +193,900000000000000000000000000000000000000000000000000000000000000193.9999999999 +194,900000000000000000000000000000000000000000000000000000000000000194.9999999999 +195,900000000000000000000000000000000000000000000000000000000000000195.9999999999 +196,900000000000000000000000000000000000000000000000000000000000000196.9999999999 +197,900000000000000000000000000000000000000000000000000000000000000197.9999999999 +198,900000000000000000000000000000000000000000000000000000000000000198.9999999999 +199,900000000000000000000000000000000000000000000000000000000000000199.9999999999 +200,900000000000000000000000000000000000000000000000000000000000000200.9999999999 +201,900000000000000000000000000000000000000000000000000000000000000201.9999999999 +202,900000000000000000000000000000000000000000000000000000000000000202.9999999999 +203,900000000000000000000000000000000000000000000000000000000000000203.9999999999 +204,900000000000000000000000000000000000000000000000000000000000000204.9999999999 +205,900000000000000000000000000000000000000000000000000000000000000205.9999999999 +206,900000000000000000000000000000000000000000000000000000000000000206.9999999999 +207,900000000000000000000000000000000000000000000000000000000000000207.9999999999 +208,900000000000000000000000000000000000000000000000000000000000000208.9999999999 +209,900000000000000000000000000000000000000000000000000000000000000209.9999999999 +210,900000000000000000000000000000000000000000000000000000000000000210.9999999999 +211,900000000000000000000000000000000000000000000000000000000000000211.9999999999 +212,900000000000000000000000000000000000000000000000000000000000000212.9999999999 +213,900000000000000000000000000000000000000000000000000000000000000213.9999999999 +214,900000000000000000000000000000000000000000000000000000000000000214.9999999999 +215,900000000000000000000000000000000000000000000000000000000000000215.9999999999 +216,900000000000000000000000000000000000000000000000000000000000000216.9999999999 +217,900000000000000000000000000000000000000000000000000000000000000217.9999999999 +218,900000000000000000000000000000000000000000000000000000000000000218.9999999999 +219,900000000000000000000000000000000000000000000000000000000000000219.9999999999 +220,900000000000000000000000000000000000000000000000000000000000000220.9999999999 +221,900000000000000000000000000000000000000000000000000000000000000221.9999999999 +222,900000000000000000000000000000000000000000000000000000000000000222.9999999999 +223,900000000000000000000000000000000000000000000000000000000000000223.9999999999 +224,900000000000000000000000000000000000000000000000000000000000000224.9999999999 +225,900000000000000000000000000000000000000000000000000000000000000225.9999999999 +226,900000000000000000000000000000000000000000000000000000000000000226.9999999999 +227,900000000000000000000000000000000000000000000000000000000000000227.9999999999 +228,900000000000000000000000000000000000000000000000000000000000000228.9999999999 +229,900000000000000000000000000000000000000000000000000000000000000229.9999999999 +230,900000000000000000000000000000000000000000000000000000000000000230.9999999999 +231,900000000000000000000000000000000000000000000000000000000000000231.9999999999 +232,900000000000000000000000000000000000000000000000000000000000000232.9999999999 +233,900000000000000000000000000000000000000000000000000000000000000233.9999999999 +234,900000000000000000000000000000000000000000000000000000000000000234.9999999999 +235,900000000000000000000000000000000000000000000000000000000000000235.9999999999 +236,900000000000000000000000000000000000000000000000000000000000000236.9999999999 +237,900000000000000000000000000000000000000000000000000000000000000237.9999999999 +238,900000000000000000000000000000000000000000000000000000000000000238.9999999999 +239,900000000000000000000000000000000000000000000000000000000000000239.9999999999 +240,900000000000000000000000000000000000000000000000000000000000000240.9999999999 +241,900000000000000000000000000000000000000000000000000000000000000241.9999999999 +242,900000000000000000000000000000000000000000000000000000000000000242.9999999999 +243,900000000000000000000000000000000000000000000000000000000000000243.9999999999 +244,900000000000000000000000000000000000000000000000000000000000000244.9999999999 +245,900000000000000000000000000000000000000000000000000000000000000245.9999999999 +246,900000000000000000000000000000000000000000000000000000000000000246.9999999999 +247,900000000000000000000000000000000000000000000000000000000000000247.9999999999 +248,900000000000000000000000000000000000000000000000000000000000000248.9999999999 +249,900000000000000000000000000000000000000000000000000000000000000249.9999999999 +250,900000000000000000000000000000000000000000000000000000000000000250.9999999999 +251,900000000000000000000000000000000000000000000000000000000000000251.9999999999 +252,900000000000000000000000000000000000000000000000000000000000000252.9999999999 +253,900000000000000000000000000000000000000000000000000000000000000253.9999999999 +254,900000000000000000000000000000000000000000000000000000000000000254.9999999999 +255,900000000000000000000000000000000000000000000000000000000000000255.9999999999 +256,900000000000000000000000000000000000000000000000000000000000000256.9999999999 +257,900000000000000000000000000000000000000000000000000000000000000257.9999999999 +258,900000000000000000000000000000000000000000000000000000000000000258.9999999999 +259,900000000000000000000000000000000000000000000000000000000000000259.9999999999 +260,900000000000000000000000000000000000000000000000000000000000000260.9999999999 +261,900000000000000000000000000000000000000000000000000000000000000261.9999999999 +262,900000000000000000000000000000000000000000000000000000000000000262.9999999999 +263,900000000000000000000000000000000000000000000000000000000000000263.9999999999 +264,900000000000000000000000000000000000000000000000000000000000000264.9999999999 +265,900000000000000000000000000000000000000000000000000000000000000265.9999999999 +266,900000000000000000000000000000000000000000000000000000000000000266.9999999999 +267,900000000000000000000000000000000000000000000000000000000000000267.9999999999 +268,900000000000000000000000000000000000000000000000000000000000000268.9999999999 +269,900000000000000000000000000000000000000000000000000000000000000269.9999999999 +270,900000000000000000000000000000000000000000000000000000000000000270.9999999999 +271,900000000000000000000000000000000000000000000000000000000000000271.9999999999 +272,900000000000000000000000000000000000000000000000000000000000000272.9999999999 +273,900000000000000000000000000000000000000000000000000000000000000273.9999999999 +274,900000000000000000000000000000000000000000000000000000000000000274.9999999999 +275,900000000000000000000000000000000000000000000000000000000000000275.9999999999 +276,900000000000000000000000000000000000000000000000000000000000000276.9999999999 +277,900000000000000000000000000000000000000000000000000000000000000277.9999999999 +278,900000000000000000000000000000000000000000000000000000000000000278.9999999999 +279,900000000000000000000000000000000000000000000000000000000000000279.9999999999 +280,900000000000000000000000000000000000000000000000000000000000000280.9999999999 +281,900000000000000000000000000000000000000000000000000000000000000281.9999999999 +282,900000000000000000000000000000000000000000000000000000000000000282.9999999999 +283,900000000000000000000000000000000000000000000000000000000000000283.9999999999 +284,900000000000000000000000000000000000000000000000000000000000000284.9999999999 +285,900000000000000000000000000000000000000000000000000000000000000285.9999999999 +286,900000000000000000000000000000000000000000000000000000000000000286.9999999999 +287,900000000000000000000000000000000000000000000000000000000000000287.9999999999 +288,900000000000000000000000000000000000000000000000000000000000000288.9999999999 +289,900000000000000000000000000000000000000000000000000000000000000289.9999999999 +290,900000000000000000000000000000000000000000000000000000000000000290.9999999999 +291,900000000000000000000000000000000000000000000000000000000000000291.9999999999 +292,900000000000000000000000000000000000000000000000000000000000000292.9999999999 +293,900000000000000000000000000000000000000000000000000000000000000293.9999999999 +294,900000000000000000000000000000000000000000000000000000000000000294.9999999999 +295,900000000000000000000000000000000000000000000000000000000000000295.9999999999 +296,900000000000000000000000000000000000000000000000000000000000000296.9999999999 +297,900000000000000000000000000000000000000000000000000000000000000297.9999999999 +298,900000000000000000000000000000000000000000000000000000000000000298.9999999999 +299,900000000000000000000000000000000000000000000000000000000000000299.9999999999 +300,900000000000000000000000000000000000000000000000000000000000000300.9999999999 +301,900000000000000000000000000000000000000000000000000000000000000301.9999999999 +302,900000000000000000000000000000000000000000000000000000000000000302.9999999999 +303,900000000000000000000000000000000000000000000000000000000000000303.9999999999 +304,900000000000000000000000000000000000000000000000000000000000000304.9999999999 +305,900000000000000000000000000000000000000000000000000000000000000305.9999999999 +306,900000000000000000000000000000000000000000000000000000000000000306.9999999999 +307,900000000000000000000000000000000000000000000000000000000000000307.9999999999 +308,900000000000000000000000000000000000000000000000000000000000000308.9999999999 +309,900000000000000000000000000000000000000000000000000000000000000309.9999999999 +310,900000000000000000000000000000000000000000000000000000000000000310.9999999999 +311,900000000000000000000000000000000000000000000000000000000000000311.9999999999 +312,900000000000000000000000000000000000000000000000000000000000000312.9999999999 +313,900000000000000000000000000000000000000000000000000000000000000313.9999999999 +314,900000000000000000000000000000000000000000000000000000000000000314.9999999999 +315,900000000000000000000000000000000000000000000000000000000000000315.9999999999 +316,900000000000000000000000000000000000000000000000000000000000000316.9999999999 +317,900000000000000000000000000000000000000000000000000000000000000317.9999999999 +318,900000000000000000000000000000000000000000000000000000000000000318.9999999999 +319,900000000000000000000000000000000000000000000000000000000000000319.9999999999 +320,900000000000000000000000000000000000000000000000000000000000000320.9999999999 +321,900000000000000000000000000000000000000000000000000000000000000321.9999999999 +322,900000000000000000000000000000000000000000000000000000000000000322.9999999999 +323,900000000000000000000000000000000000000000000000000000000000000323.9999999999 +324,900000000000000000000000000000000000000000000000000000000000000324.9999999999 +325,900000000000000000000000000000000000000000000000000000000000000325.9999999999 +326,900000000000000000000000000000000000000000000000000000000000000326.9999999999 +327,900000000000000000000000000000000000000000000000000000000000000327.9999999999 +328,900000000000000000000000000000000000000000000000000000000000000328.9999999999 +329,900000000000000000000000000000000000000000000000000000000000000329.9999999999 +330,900000000000000000000000000000000000000000000000000000000000000330.9999999999 +331,900000000000000000000000000000000000000000000000000000000000000331.9999999999 +332,900000000000000000000000000000000000000000000000000000000000000332.9999999999 +333,900000000000000000000000000000000000000000000000000000000000000333.9999999999 +334,900000000000000000000000000000000000000000000000000000000000000334.9999999999 +335,900000000000000000000000000000000000000000000000000000000000000335.9999999999 +336,900000000000000000000000000000000000000000000000000000000000000336.9999999999 +337,900000000000000000000000000000000000000000000000000000000000000337.9999999999 +338,900000000000000000000000000000000000000000000000000000000000000338.9999999999 +339,900000000000000000000000000000000000000000000000000000000000000339.9999999999 +340,900000000000000000000000000000000000000000000000000000000000000340.9999999999 +341,900000000000000000000000000000000000000000000000000000000000000341.9999999999 +342,900000000000000000000000000000000000000000000000000000000000000342.9999999999 +343,900000000000000000000000000000000000000000000000000000000000000343.9999999999 +344,900000000000000000000000000000000000000000000000000000000000000344.9999999999 +345,900000000000000000000000000000000000000000000000000000000000000345.9999999999 +346,900000000000000000000000000000000000000000000000000000000000000346.9999999999 +347,900000000000000000000000000000000000000000000000000000000000000347.9999999999 +348,900000000000000000000000000000000000000000000000000000000000000348.9999999999 +349,900000000000000000000000000000000000000000000000000000000000000349.9999999999 +350,900000000000000000000000000000000000000000000000000000000000000350.9999999999 +351,900000000000000000000000000000000000000000000000000000000000000351.9999999999 +352,900000000000000000000000000000000000000000000000000000000000000352.9999999999 +353,900000000000000000000000000000000000000000000000000000000000000353.9999999999 +354,900000000000000000000000000000000000000000000000000000000000000354.9999999999 +355,900000000000000000000000000000000000000000000000000000000000000355.9999999999 +356,900000000000000000000000000000000000000000000000000000000000000356.9999999999 +357,900000000000000000000000000000000000000000000000000000000000000357.9999999999 +358,900000000000000000000000000000000000000000000000000000000000000358.9999999999 +359,900000000000000000000000000000000000000000000000000000000000000359.9999999999 +360,900000000000000000000000000000000000000000000000000000000000000360.9999999999 +361,900000000000000000000000000000000000000000000000000000000000000361.9999999999 +362,900000000000000000000000000000000000000000000000000000000000000362.9999999999 +363,900000000000000000000000000000000000000000000000000000000000000363.9999999999 +364,900000000000000000000000000000000000000000000000000000000000000364.9999999999 +365,900000000000000000000000000000000000000000000000000000000000000365.9999999999 +366,900000000000000000000000000000000000000000000000000000000000000366.9999999999 +367,900000000000000000000000000000000000000000000000000000000000000367.9999999999 +368,900000000000000000000000000000000000000000000000000000000000000368.9999999999 +369,900000000000000000000000000000000000000000000000000000000000000369.9999999999 +370,900000000000000000000000000000000000000000000000000000000000000370.9999999999 +371,900000000000000000000000000000000000000000000000000000000000000371.9999999999 +372,900000000000000000000000000000000000000000000000000000000000000372.9999999999 +373,900000000000000000000000000000000000000000000000000000000000000373.9999999999 +374,900000000000000000000000000000000000000000000000000000000000000374.9999999999 +375,900000000000000000000000000000000000000000000000000000000000000375.9999999999 +376,900000000000000000000000000000000000000000000000000000000000000376.9999999999 +377,900000000000000000000000000000000000000000000000000000000000000377.9999999999 +378,900000000000000000000000000000000000000000000000000000000000000378.9999999999 +379,900000000000000000000000000000000000000000000000000000000000000379.9999999999 +380,900000000000000000000000000000000000000000000000000000000000000380.9999999999 +381,900000000000000000000000000000000000000000000000000000000000000381.9999999999 +382,900000000000000000000000000000000000000000000000000000000000000382.9999999999 +383,900000000000000000000000000000000000000000000000000000000000000383.9999999999 +384,900000000000000000000000000000000000000000000000000000000000000384.9999999999 +385,900000000000000000000000000000000000000000000000000000000000000385.9999999999 +386,900000000000000000000000000000000000000000000000000000000000000386.9999999999 +387,900000000000000000000000000000000000000000000000000000000000000387.9999999999 +388,900000000000000000000000000000000000000000000000000000000000000388.9999999999 +389,900000000000000000000000000000000000000000000000000000000000000389.9999999999 +390,900000000000000000000000000000000000000000000000000000000000000390.9999999999 +391,900000000000000000000000000000000000000000000000000000000000000391.9999999999 +392,900000000000000000000000000000000000000000000000000000000000000392.9999999999 +393,900000000000000000000000000000000000000000000000000000000000000393.9999999999 +394,900000000000000000000000000000000000000000000000000000000000000394.9999999999 +395,900000000000000000000000000000000000000000000000000000000000000395.9999999999 +396,900000000000000000000000000000000000000000000000000000000000000396.9999999999 +397,900000000000000000000000000000000000000000000000000000000000000397.9999999999 +398,900000000000000000000000000000000000000000000000000000000000000398.9999999999 +399,900000000000000000000000000000000000000000000000000000000000000399.9999999999 +400,900000000000000000000000000000000000000000000000000000000000000400.9999999999 +401,900000000000000000000000000000000000000000000000000000000000000401.9999999999 +402,900000000000000000000000000000000000000000000000000000000000000402.9999999999 +403,900000000000000000000000000000000000000000000000000000000000000403.9999999999 +404,900000000000000000000000000000000000000000000000000000000000000404.9999999999 +405,900000000000000000000000000000000000000000000000000000000000000405.9999999999 +406,900000000000000000000000000000000000000000000000000000000000000406.9999999999 +407,900000000000000000000000000000000000000000000000000000000000000407.9999999999 +408,900000000000000000000000000000000000000000000000000000000000000408.9999999999 +409,900000000000000000000000000000000000000000000000000000000000000409.9999999999 +410,900000000000000000000000000000000000000000000000000000000000000410.9999999999 +411,900000000000000000000000000000000000000000000000000000000000000411.9999999999 +412,900000000000000000000000000000000000000000000000000000000000000412.9999999999 +413,900000000000000000000000000000000000000000000000000000000000000413.9999999999 +414,900000000000000000000000000000000000000000000000000000000000000414.9999999999 +415,900000000000000000000000000000000000000000000000000000000000000415.9999999999 +416,900000000000000000000000000000000000000000000000000000000000000416.9999999999 +417,900000000000000000000000000000000000000000000000000000000000000417.9999999999 +418,900000000000000000000000000000000000000000000000000000000000000418.9999999999 +419,900000000000000000000000000000000000000000000000000000000000000419.9999999999 +420,900000000000000000000000000000000000000000000000000000000000000420.9999999999 +421,900000000000000000000000000000000000000000000000000000000000000421.9999999999 +422,900000000000000000000000000000000000000000000000000000000000000422.9999999999 +423,900000000000000000000000000000000000000000000000000000000000000423.9999999999 +424,900000000000000000000000000000000000000000000000000000000000000424.9999999999 +425,900000000000000000000000000000000000000000000000000000000000000425.9999999999 +426,900000000000000000000000000000000000000000000000000000000000000426.9999999999 +427,900000000000000000000000000000000000000000000000000000000000000427.9999999999 +428,900000000000000000000000000000000000000000000000000000000000000428.9999999999 +429,900000000000000000000000000000000000000000000000000000000000000429.9999999999 +430,900000000000000000000000000000000000000000000000000000000000000430.9999999999 +431,900000000000000000000000000000000000000000000000000000000000000431.9999999999 +432,900000000000000000000000000000000000000000000000000000000000000432.9999999999 +433,900000000000000000000000000000000000000000000000000000000000000433.9999999999 +434,900000000000000000000000000000000000000000000000000000000000000434.9999999999 +435,900000000000000000000000000000000000000000000000000000000000000435.9999999999 +436,900000000000000000000000000000000000000000000000000000000000000436.9999999999 +437,900000000000000000000000000000000000000000000000000000000000000437.9999999999 +438,900000000000000000000000000000000000000000000000000000000000000438.9999999999 +439,900000000000000000000000000000000000000000000000000000000000000439.9999999999 +440,900000000000000000000000000000000000000000000000000000000000000440.9999999999 +441,900000000000000000000000000000000000000000000000000000000000000441.9999999999 +442,900000000000000000000000000000000000000000000000000000000000000442.9999999999 +443,900000000000000000000000000000000000000000000000000000000000000443.9999999999 +444,900000000000000000000000000000000000000000000000000000000000000444.9999999999 +445,900000000000000000000000000000000000000000000000000000000000000445.9999999999 +446,900000000000000000000000000000000000000000000000000000000000000446.9999999999 +447,900000000000000000000000000000000000000000000000000000000000000447.9999999999 +448,900000000000000000000000000000000000000000000000000000000000000448.9999999999 +449,900000000000000000000000000000000000000000000000000000000000000449.9999999999 +450,900000000000000000000000000000000000000000000000000000000000000450.9999999999 +451,900000000000000000000000000000000000000000000000000000000000000451.9999999999 +452,900000000000000000000000000000000000000000000000000000000000000452.9999999999 +453,900000000000000000000000000000000000000000000000000000000000000453.9999999999 +454,900000000000000000000000000000000000000000000000000000000000000454.9999999999 +455,900000000000000000000000000000000000000000000000000000000000000455.9999999999 +456,900000000000000000000000000000000000000000000000000000000000000456.9999999999 +457,900000000000000000000000000000000000000000000000000000000000000457.9999999999 +458,900000000000000000000000000000000000000000000000000000000000000458.9999999999 +459,900000000000000000000000000000000000000000000000000000000000000459.9999999999 +460,900000000000000000000000000000000000000000000000000000000000000460.9999999999 +461,900000000000000000000000000000000000000000000000000000000000000461.9999999999 +462,900000000000000000000000000000000000000000000000000000000000000462.9999999999 +463,900000000000000000000000000000000000000000000000000000000000000463.9999999999 +464,900000000000000000000000000000000000000000000000000000000000000464.9999999999 +465,900000000000000000000000000000000000000000000000000000000000000465.9999999999 +466,900000000000000000000000000000000000000000000000000000000000000466.9999999999 +467,900000000000000000000000000000000000000000000000000000000000000467.9999999999 +468,900000000000000000000000000000000000000000000000000000000000000468.9999999999 +469,900000000000000000000000000000000000000000000000000000000000000469.9999999999 +470,900000000000000000000000000000000000000000000000000000000000000470.9999999999 +471,900000000000000000000000000000000000000000000000000000000000000471.9999999999 +472,900000000000000000000000000000000000000000000000000000000000000472.9999999999 +473,900000000000000000000000000000000000000000000000000000000000000473.9999999999 +474,900000000000000000000000000000000000000000000000000000000000000474.9999999999 +475,900000000000000000000000000000000000000000000000000000000000000475.9999999999 +476,900000000000000000000000000000000000000000000000000000000000000476.9999999999 +477,900000000000000000000000000000000000000000000000000000000000000477.9999999999 +478,900000000000000000000000000000000000000000000000000000000000000478.9999999999 +479,900000000000000000000000000000000000000000000000000000000000000479.9999999999 +480,900000000000000000000000000000000000000000000000000000000000000480.9999999999 +481,900000000000000000000000000000000000000000000000000000000000000481.9999999999 +482,900000000000000000000000000000000000000000000000000000000000000482.9999999999 +483,900000000000000000000000000000000000000000000000000000000000000483.9999999999 +484,900000000000000000000000000000000000000000000000000000000000000484.9999999999 +485,900000000000000000000000000000000000000000000000000000000000000485.9999999999 +486,900000000000000000000000000000000000000000000000000000000000000486.9999999999 +487,900000000000000000000000000000000000000000000000000000000000000487.9999999999 +488,900000000000000000000000000000000000000000000000000000000000000488.9999999999 +489,900000000000000000000000000000000000000000000000000000000000000489.9999999999 +490,900000000000000000000000000000000000000000000000000000000000000490.9999999999 +491,900000000000000000000000000000000000000000000000000000000000000491.9999999999 +492,900000000000000000000000000000000000000000000000000000000000000492.9999999999 +493,900000000000000000000000000000000000000000000000000000000000000493.9999999999 +494,900000000000000000000000000000000000000000000000000000000000000494.9999999999 +495,900000000000000000000000000000000000000000000000000000000000000495.9999999999 +496,900000000000000000000000000000000000000000000000000000000000000496.9999999999 +497,900000000000000000000000000000000000000000000000000000000000000497.9999999999 +498,900000000000000000000000000000000000000000000000000000000000000498.9999999999 +499,900000000000000000000000000000000000000000000000000000000000000499.9999999999 +500,900000000000000000000000000000000000000000000000000000000000000500.9999999999 +501,900000000000000000000000000000000000000000000000000000000000000501.9999999999 +502,900000000000000000000000000000000000000000000000000000000000000502.9999999999 +503,900000000000000000000000000000000000000000000000000000000000000503.9999999999 +504,900000000000000000000000000000000000000000000000000000000000000504.9999999999 +505,900000000000000000000000000000000000000000000000000000000000000505.9999999999 +506,900000000000000000000000000000000000000000000000000000000000000506.9999999999 +507,900000000000000000000000000000000000000000000000000000000000000507.9999999999 +508,900000000000000000000000000000000000000000000000000000000000000508.9999999999 +509,900000000000000000000000000000000000000000000000000000000000000509.9999999999 +510,900000000000000000000000000000000000000000000000000000000000000510.9999999999 +511,900000000000000000000000000000000000000000000000000000000000000511.9999999999 +512,900000000000000000000000000000000000000000000000000000000000000512.9999999999 +513,900000000000000000000000000000000000000000000000000000000000000513.9999999999 +514,900000000000000000000000000000000000000000000000000000000000000514.9999999999 +515,900000000000000000000000000000000000000000000000000000000000000515.9999999999 +516,900000000000000000000000000000000000000000000000000000000000000516.9999999999 +517,900000000000000000000000000000000000000000000000000000000000000517.9999999999 +518,900000000000000000000000000000000000000000000000000000000000000518.9999999999 +519,900000000000000000000000000000000000000000000000000000000000000519.9999999999 +520,900000000000000000000000000000000000000000000000000000000000000520.9999999999 +521,900000000000000000000000000000000000000000000000000000000000000521.9999999999 +522,900000000000000000000000000000000000000000000000000000000000000522.9999999999 +523,900000000000000000000000000000000000000000000000000000000000000523.9999999999 +524,900000000000000000000000000000000000000000000000000000000000000524.9999999999 +525,900000000000000000000000000000000000000000000000000000000000000525.9999999999 +526,900000000000000000000000000000000000000000000000000000000000000526.9999999999 +527,900000000000000000000000000000000000000000000000000000000000000527.9999999999 +528,900000000000000000000000000000000000000000000000000000000000000528.9999999999 +529,900000000000000000000000000000000000000000000000000000000000000529.9999999999 +530,900000000000000000000000000000000000000000000000000000000000000530.9999999999 +531,900000000000000000000000000000000000000000000000000000000000000531.9999999999 +532,900000000000000000000000000000000000000000000000000000000000000532.9999999999 +533,900000000000000000000000000000000000000000000000000000000000000533.9999999999 +534,900000000000000000000000000000000000000000000000000000000000000534.9999999999 +535,900000000000000000000000000000000000000000000000000000000000000535.9999999999 +536,900000000000000000000000000000000000000000000000000000000000000536.9999999999 +537,900000000000000000000000000000000000000000000000000000000000000537.9999999999 +538,900000000000000000000000000000000000000000000000000000000000000538.9999999999 +539,900000000000000000000000000000000000000000000000000000000000000539.9999999999 +540,900000000000000000000000000000000000000000000000000000000000000540.9999999999 +541,900000000000000000000000000000000000000000000000000000000000000541.9999999999 +542,900000000000000000000000000000000000000000000000000000000000000542.9999999999 +543,900000000000000000000000000000000000000000000000000000000000000543.9999999999 +544,900000000000000000000000000000000000000000000000000000000000000544.9999999999 +545,900000000000000000000000000000000000000000000000000000000000000545.9999999999 +546,900000000000000000000000000000000000000000000000000000000000000546.9999999999 +547,900000000000000000000000000000000000000000000000000000000000000547.9999999999 +548,900000000000000000000000000000000000000000000000000000000000000548.9999999999 +549,900000000000000000000000000000000000000000000000000000000000000549.9999999999 +550,900000000000000000000000000000000000000000000000000000000000000550.9999999999 +551,900000000000000000000000000000000000000000000000000000000000000551.9999999999 +552,900000000000000000000000000000000000000000000000000000000000000552.9999999999 +553,900000000000000000000000000000000000000000000000000000000000000553.9999999999 +554,900000000000000000000000000000000000000000000000000000000000000554.9999999999 +555,900000000000000000000000000000000000000000000000000000000000000555.9999999999 +556,900000000000000000000000000000000000000000000000000000000000000556.9999999999 +557,900000000000000000000000000000000000000000000000000000000000000557.9999999999 +558,900000000000000000000000000000000000000000000000000000000000000558.9999999999 +559,900000000000000000000000000000000000000000000000000000000000000559.9999999999 +560,900000000000000000000000000000000000000000000000000000000000000560.9999999999 +561,900000000000000000000000000000000000000000000000000000000000000561.9999999999 +562,900000000000000000000000000000000000000000000000000000000000000562.9999999999 +563,900000000000000000000000000000000000000000000000000000000000000563.9999999999 +564,900000000000000000000000000000000000000000000000000000000000000564.9999999999 +565,900000000000000000000000000000000000000000000000000000000000000565.9999999999 +566,900000000000000000000000000000000000000000000000000000000000000566.9999999999 +567,900000000000000000000000000000000000000000000000000000000000000567.9999999999 +568,900000000000000000000000000000000000000000000000000000000000000568.9999999999 +569,900000000000000000000000000000000000000000000000000000000000000569.9999999999 +570,900000000000000000000000000000000000000000000000000000000000000570.9999999999 +571,900000000000000000000000000000000000000000000000000000000000000571.9999999999 +572,900000000000000000000000000000000000000000000000000000000000000572.9999999999 +573,900000000000000000000000000000000000000000000000000000000000000573.9999999999 +574,900000000000000000000000000000000000000000000000000000000000000574.9999999999 +575,900000000000000000000000000000000000000000000000000000000000000575.9999999999 +576,900000000000000000000000000000000000000000000000000000000000000576.9999999999 +577,900000000000000000000000000000000000000000000000000000000000000577.9999999999 +578,900000000000000000000000000000000000000000000000000000000000000578.9999999999 +579,900000000000000000000000000000000000000000000000000000000000000579.9999999999 +580,900000000000000000000000000000000000000000000000000000000000000580.9999999999 +581,900000000000000000000000000000000000000000000000000000000000000581.9999999999 +582,900000000000000000000000000000000000000000000000000000000000000582.9999999999 +583,900000000000000000000000000000000000000000000000000000000000000583.9999999999 +584,900000000000000000000000000000000000000000000000000000000000000584.9999999999 +585,900000000000000000000000000000000000000000000000000000000000000585.9999999999 +586,900000000000000000000000000000000000000000000000000000000000000586.9999999999 +587,900000000000000000000000000000000000000000000000000000000000000587.9999999999 +588,900000000000000000000000000000000000000000000000000000000000000588.9999999999 +589,900000000000000000000000000000000000000000000000000000000000000589.9999999999 +590,900000000000000000000000000000000000000000000000000000000000000590.9999999999 +591,900000000000000000000000000000000000000000000000000000000000000591.9999999999 +592,900000000000000000000000000000000000000000000000000000000000000592.9999999999 +593,900000000000000000000000000000000000000000000000000000000000000593.9999999999 +594,900000000000000000000000000000000000000000000000000000000000000594.9999999999 +595,900000000000000000000000000000000000000000000000000000000000000595.9999999999 +596,900000000000000000000000000000000000000000000000000000000000000596.9999999999 +597,900000000000000000000000000000000000000000000000000000000000000597.9999999999 +598,900000000000000000000000000000000000000000000000000000000000000598.9999999999 +599,900000000000000000000000000000000000000000000000000000000000000599.9999999999 +600,900000000000000000000000000000000000000000000000000000000000000600.9999999999 +601,900000000000000000000000000000000000000000000000000000000000000601.9999999999 +602,900000000000000000000000000000000000000000000000000000000000000602.9999999999 +603,900000000000000000000000000000000000000000000000000000000000000603.9999999999 +604,900000000000000000000000000000000000000000000000000000000000000604.9999999999 +605,900000000000000000000000000000000000000000000000000000000000000605.9999999999 +606,900000000000000000000000000000000000000000000000000000000000000606.9999999999 +607,900000000000000000000000000000000000000000000000000000000000000607.9999999999 +608,900000000000000000000000000000000000000000000000000000000000000608.9999999999 +609,900000000000000000000000000000000000000000000000000000000000000609.9999999999 +610,900000000000000000000000000000000000000000000000000000000000000610.9999999999 +611,900000000000000000000000000000000000000000000000000000000000000611.9999999999 +612,900000000000000000000000000000000000000000000000000000000000000612.9999999999 +613,900000000000000000000000000000000000000000000000000000000000000613.9999999999 +614,900000000000000000000000000000000000000000000000000000000000000614.9999999999 +615,900000000000000000000000000000000000000000000000000000000000000615.9999999999 +616,900000000000000000000000000000000000000000000000000000000000000616.9999999999 +617,900000000000000000000000000000000000000000000000000000000000000617.9999999999 +618,900000000000000000000000000000000000000000000000000000000000000618.9999999999 +619,900000000000000000000000000000000000000000000000000000000000000619.9999999999 +620,900000000000000000000000000000000000000000000000000000000000000620.9999999999 +621,900000000000000000000000000000000000000000000000000000000000000621.9999999999 +622,900000000000000000000000000000000000000000000000000000000000000622.9999999999 +623,900000000000000000000000000000000000000000000000000000000000000623.9999999999 +624,900000000000000000000000000000000000000000000000000000000000000624.9999999999 +625,900000000000000000000000000000000000000000000000000000000000000625.9999999999 +626,900000000000000000000000000000000000000000000000000000000000000626.9999999999 +627,900000000000000000000000000000000000000000000000000000000000000627.9999999999 +628,900000000000000000000000000000000000000000000000000000000000000628.9999999999 +629,900000000000000000000000000000000000000000000000000000000000000629.9999999999 +630,900000000000000000000000000000000000000000000000000000000000000630.9999999999 +631,900000000000000000000000000000000000000000000000000000000000000631.9999999999 +632,900000000000000000000000000000000000000000000000000000000000000632.9999999999 +633,900000000000000000000000000000000000000000000000000000000000000633.9999999999 +634,900000000000000000000000000000000000000000000000000000000000000634.9999999999 +635,900000000000000000000000000000000000000000000000000000000000000635.9999999999 +636,900000000000000000000000000000000000000000000000000000000000000636.9999999999 +637,900000000000000000000000000000000000000000000000000000000000000637.9999999999 +638,900000000000000000000000000000000000000000000000000000000000000638.9999999999 +639,900000000000000000000000000000000000000000000000000000000000000639.9999999999 +640,900000000000000000000000000000000000000000000000000000000000000640.9999999999 +641,900000000000000000000000000000000000000000000000000000000000000641.9999999999 +642,900000000000000000000000000000000000000000000000000000000000000642.9999999999 +643,900000000000000000000000000000000000000000000000000000000000000643.9999999999 +644,900000000000000000000000000000000000000000000000000000000000000644.9999999999 +645,900000000000000000000000000000000000000000000000000000000000000645.9999999999 +646,900000000000000000000000000000000000000000000000000000000000000646.9999999999 +647,900000000000000000000000000000000000000000000000000000000000000647.9999999999 +648,900000000000000000000000000000000000000000000000000000000000000648.9999999999 +649,900000000000000000000000000000000000000000000000000000000000000649.9999999999 +650,900000000000000000000000000000000000000000000000000000000000000650.9999999999 +651,900000000000000000000000000000000000000000000000000000000000000651.9999999999 +652,900000000000000000000000000000000000000000000000000000000000000652.9999999999 +653,900000000000000000000000000000000000000000000000000000000000000653.9999999999 +654,900000000000000000000000000000000000000000000000000000000000000654.9999999999 +655,900000000000000000000000000000000000000000000000000000000000000655.9999999999 +656,900000000000000000000000000000000000000000000000000000000000000656.9999999999 +657,900000000000000000000000000000000000000000000000000000000000000657.9999999999 +658,900000000000000000000000000000000000000000000000000000000000000658.9999999999 +659,900000000000000000000000000000000000000000000000000000000000000659.9999999999 +660,900000000000000000000000000000000000000000000000000000000000000660.9999999999 +661,900000000000000000000000000000000000000000000000000000000000000661.9999999999 +662,900000000000000000000000000000000000000000000000000000000000000662.9999999999 +663,900000000000000000000000000000000000000000000000000000000000000663.9999999999 +664,900000000000000000000000000000000000000000000000000000000000000664.9999999999 +665,900000000000000000000000000000000000000000000000000000000000000665.9999999999 +666,900000000000000000000000000000000000000000000000000000000000000666.9999999999 +667,900000000000000000000000000000000000000000000000000000000000000667.9999999999 +668,900000000000000000000000000000000000000000000000000000000000000668.9999999999 +669,900000000000000000000000000000000000000000000000000000000000000669.9999999999 +670,900000000000000000000000000000000000000000000000000000000000000670.9999999999 +671,900000000000000000000000000000000000000000000000000000000000000671.9999999999 +672,900000000000000000000000000000000000000000000000000000000000000672.9999999999 +673,900000000000000000000000000000000000000000000000000000000000000673.9999999999 +674,900000000000000000000000000000000000000000000000000000000000000674.9999999999 +675,900000000000000000000000000000000000000000000000000000000000000675.9999999999 +676,900000000000000000000000000000000000000000000000000000000000000676.9999999999 +677,900000000000000000000000000000000000000000000000000000000000000677.9999999999 +678,900000000000000000000000000000000000000000000000000000000000000678.9999999999 +679,900000000000000000000000000000000000000000000000000000000000000679.9999999999 +680,900000000000000000000000000000000000000000000000000000000000000680.9999999999 +681,900000000000000000000000000000000000000000000000000000000000000681.9999999999 +682,900000000000000000000000000000000000000000000000000000000000000682.9999999999 +683,900000000000000000000000000000000000000000000000000000000000000683.9999999999 +684,900000000000000000000000000000000000000000000000000000000000000684.9999999999 +685,900000000000000000000000000000000000000000000000000000000000000685.9999999999 +686,900000000000000000000000000000000000000000000000000000000000000686.9999999999 +687,900000000000000000000000000000000000000000000000000000000000000687.9999999999 +688,900000000000000000000000000000000000000000000000000000000000000688.9999999999 +689,900000000000000000000000000000000000000000000000000000000000000689.9999999999 +690,900000000000000000000000000000000000000000000000000000000000000690.9999999999 +691,900000000000000000000000000000000000000000000000000000000000000691.9999999999 +692,900000000000000000000000000000000000000000000000000000000000000692.9999999999 +693,900000000000000000000000000000000000000000000000000000000000000693.9999999999 +694,900000000000000000000000000000000000000000000000000000000000000694.9999999999 +695,900000000000000000000000000000000000000000000000000000000000000695.9999999999 +696,900000000000000000000000000000000000000000000000000000000000000696.9999999999 +697,900000000000000000000000000000000000000000000000000000000000000697.9999999999 +698,900000000000000000000000000000000000000000000000000000000000000698.9999999999 +699,900000000000000000000000000000000000000000000000000000000000000699.9999999999 +700,900000000000000000000000000000000000000000000000000000000000000700.9999999999 +701,900000000000000000000000000000000000000000000000000000000000000701.9999999999 +702,900000000000000000000000000000000000000000000000000000000000000702.9999999999 +703,900000000000000000000000000000000000000000000000000000000000000703.9999999999 +704,900000000000000000000000000000000000000000000000000000000000000704.9999999999 +705,900000000000000000000000000000000000000000000000000000000000000705.9999999999 +706,900000000000000000000000000000000000000000000000000000000000000706.9999999999 +707,900000000000000000000000000000000000000000000000000000000000000707.9999999999 +708,900000000000000000000000000000000000000000000000000000000000000708.9999999999 +709,900000000000000000000000000000000000000000000000000000000000000709.9999999999 +710,900000000000000000000000000000000000000000000000000000000000000710.9999999999 +711,900000000000000000000000000000000000000000000000000000000000000711.9999999999 +712,900000000000000000000000000000000000000000000000000000000000000712.9999999999 +713,900000000000000000000000000000000000000000000000000000000000000713.9999999999 +714,900000000000000000000000000000000000000000000000000000000000000714.9999999999 +715,900000000000000000000000000000000000000000000000000000000000000715.9999999999 +716,900000000000000000000000000000000000000000000000000000000000000716.9999999999 +717,900000000000000000000000000000000000000000000000000000000000000717.9999999999 +718,900000000000000000000000000000000000000000000000000000000000000718.9999999999 +719,900000000000000000000000000000000000000000000000000000000000000719.9999999999 +720,900000000000000000000000000000000000000000000000000000000000000720.9999999999 +721,900000000000000000000000000000000000000000000000000000000000000721.9999999999 +722,900000000000000000000000000000000000000000000000000000000000000722.9999999999 +723,900000000000000000000000000000000000000000000000000000000000000723.9999999999 +724,900000000000000000000000000000000000000000000000000000000000000724.9999999999 +725,900000000000000000000000000000000000000000000000000000000000000725.9999999999 +726,900000000000000000000000000000000000000000000000000000000000000726.9999999999 +727,900000000000000000000000000000000000000000000000000000000000000727.9999999999 +728,900000000000000000000000000000000000000000000000000000000000000728.9999999999 +729,900000000000000000000000000000000000000000000000000000000000000729.9999999999 +730,900000000000000000000000000000000000000000000000000000000000000730.9999999999 +731,900000000000000000000000000000000000000000000000000000000000000731.9999999999 +732,900000000000000000000000000000000000000000000000000000000000000732.9999999999 +733,900000000000000000000000000000000000000000000000000000000000000733.9999999999 +734,900000000000000000000000000000000000000000000000000000000000000734.9999999999 +735,900000000000000000000000000000000000000000000000000000000000000735.9999999999 +736,900000000000000000000000000000000000000000000000000000000000000736.9999999999 +737,900000000000000000000000000000000000000000000000000000000000000737.9999999999 +738,900000000000000000000000000000000000000000000000000000000000000738.9999999999 +739,900000000000000000000000000000000000000000000000000000000000000739.9999999999 +740,900000000000000000000000000000000000000000000000000000000000000740.9999999999 +741,900000000000000000000000000000000000000000000000000000000000000741.9999999999 +742,900000000000000000000000000000000000000000000000000000000000000742.9999999999 +743,900000000000000000000000000000000000000000000000000000000000000743.9999999999 +744,900000000000000000000000000000000000000000000000000000000000000744.9999999999 +745,900000000000000000000000000000000000000000000000000000000000000745.9999999999 +746,900000000000000000000000000000000000000000000000000000000000000746.9999999999 +747,900000000000000000000000000000000000000000000000000000000000000747.9999999999 +748,900000000000000000000000000000000000000000000000000000000000000748.9999999999 +749,900000000000000000000000000000000000000000000000000000000000000749.9999999999 +750,900000000000000000000000000000000000000000000000000000000000000750.9999999999 +751,900000000000000000000000000000000000000000000000000000000000000751.9999999999 +752,900000000000000000000000000000000000000000000000000000000000000752.9999999999 +753,900000000000000000000000000000000000000000000000000000000000000753.9999999999 +754,900000000000000000000000000000000000000000000000000000000000000754.9999999999 +755,900000000000000000000000000000000000000000000000000000000000000755.9999999999 +756,900000000000000000000000000000000000000000000000000000000000000756.9999999999 +757,900000000000000000000000000000000000000000000000000000000000000757.9999999999 +758,900000000000000000000000000000000000000000000000000000000000000758.9999999999 +759,900000000000000000000000000000000000000000000000000000000000000759.9999999999 +760,900000000000000000000000000000000000000000000000000000000000000760.9999999999 +761,900000000000000000000000000000000000000000000000000000000000000761.9999999999 +762,900000000000000000000000000000000000000000000000000000000000000762.9999999999 +763,900000000000000000000000000000000000000000000000000000000000000763.9999999999 +764,900000000000000000000000000000000000000000000000000000000000000764.9999999999 +765,900000000000000000000000000000000000000000000000000000000000000765.9999999999 +766,900000000000000000000000000000000000000000000000000000000000000766.9999999999 +767,900000000000000000000000000000000000000000000000000000000000000767.9999999999 +768,900000000000000000000000000000000000000000000000000000000000000768.9999999999 +769,900000000000000000000000000000000000000000000000000000000000000769.9999999999 +770,900000000000000000000000000000000000000000000000000000000000000770.9999999999 +771,900000000000000000000000000000000000000000000000000000000000000771.9999999999 +772,900000000000000000000000000000000000000000000000000000000000000772.9999999999 +773,900000000000000000000000000000000000000000000000000000000000000773.9999999999 +774,900000000000000000000000000000000000000000000000000000000000000774.9999999999 +775,900000000000000000000000000000000000000000000000000000000000000775.9999999999 +776,900000000000000000000000000000000000000000000000000000000000000776.9999999999 +777,900000000000000000000000000000000000000000000000000000000000000777.9999999999 +778,900000000000000000000000000000000000000000000000000000000000000778.9999999999 +779,900000000000000000000000000000000000000000000000000000000000000779.9999999999 +780,900000000000000000000000000000000000000000000000000000000000000780.9999999999 +781,900000000000000000000000000000000000000000000000000000000000000781.9999999999 +782,900000000000000000000000000000000000000000000000000000000000000782.9999999999 +783,900000000000000000000000000000000000000000000000000000000000000783.9999999999 +784,900000000000000000000000000000000000000000000000000000000000000784.9999999999 +785,900000000000000000000000000000000000000000000000000000000000000785.9999999999 +786,900000000000000000000000000000000000000000000000000000000000000786.9999999999 +787,900000000000000000000000000000000000000000000000000000000000000787.9999999999 +788,900000000000000000000000000000000000000000000000000000000000000788.9999999999 +789,900000000000000000000000000000000000000000000000000000000000000789.9999999999 +790,900000000000000000000000000000000000000000000000000000000000000790.9999999999 +791,900000000000000000000000000000000000000000000000000000000000000791.9999999999 +792,900000000000000000000000000000000000000000000000000000000000000792.9999999999 +793,900000000000000000000000000000000000000000000000000000000000000793.9999999999 +794,900000000000000000000000000000000000000000000000000000000000000794.9999999999 +795,900000000000000000000000000000000000000000000000000000000000000795.9999999999 +796,900000000000000000000000000000000000000000000000000000000000000796.9999999999 +797,900000000000000000000000000000000000000000000000000000000000000797.9999999999 +798,900000000000000000000000000000000000000000000000000000000000000798.9999999999 +799,900000000000000000000000000000000000000000000000000000000000000799.9999999999 +800,900000000000000000000000000000000000000000000000000000000000000800.9999999999 +801,900000000000000000000000000000000000000000000000000000000000000801.9999999999 +802,900000000000000000000000000000000000000000000000000000000000000802.9999999999 +803,900000000000000000000000000000000000000000000000000000000000000803.9999999999 +804,900000000000000000000000000000000000000000000000000000000000000804.9999999999 +805,900000000000000000000000000000000000000000000000000000000000000805.9999999999 +806,900000000000000000000000000000000000000000000000000000000000000806.9999999999 +807,900000000000000000000000000000000000000000000000000000000000000807.9999999999 +808,900000000000000000000000000000000000000000000000000000000000000808.9999999999 +809,900000000000000000000000000000000000000000000000000000000000000809.9999999999 +810,900000000000000000000000000000000000000000000000000000000000000810.9999999999 +811,900000000000000000000000000000000000000000000000000000000000000811.9999999999 +812,900000000000000000000000000000000000000000000000000000000000000812.9999999999 +813,900000000000000000000000000000000000000000000000000000000000000813.9999999999 +814,900000000000000000000000000000000000000000000000000000000000000814.9999999999 +815,900000000000000000000000000000000000000000000000000000000000000815.9999999999 +816,900000000000000000000000000000000000000000000000000000000000000816.9999999999 +817,900000000000000000000000000000000000000000000000000000000000000817.9999999999 +818,900000000000000000000000000000000000000000000000000000000000000818.9999999999 +819,900000000000000000000000000000000000000000000000000000000000000819.9999999999 +820,900000000000000000000000000000000000000000000000000000000000000820.9999999999 +821,900000000000000000000000000000000000000000000000000000000000000821.9999999999 +822,900000000000000000000000000000000000000000000000000000000000000822.9999999999 +823,900000000000000000000000000000000000000000000000000000000000000823.9999999999 +824,900000000000000000000000000000000000000000000000000000000000000824.9999999999 +825,900000000000000000000000000000000000000000000000000000000000000825.9999999999 +826,900000000000000000000000000000000000000000000000000000000000000826.9999999999 +827,900000000000000000000000000000000000000000000000000000000000000827.9999999999 +828,900000000000000000000000000000000000000000000000000000000000000828.9999999999 +829,900000000000000000000000000000000000000000000000000000000000000829.9999999999 +830,900000000000000000000000000000000000000000000000000000000000000830.9999999999 +831,900000000000000000000000000000000000000000000000000000000000000831.9999999999 +832,900000000000000000000000000000000000000000000000000000000000000832.9999999999 +833,900000000000000000000000000000000000000000000000000000000000000833.9999999999 +834,900000000000000000000000000000000000000000000000000000000000000834.9999999999 +835,900000000000000000000000000000000000000000000000000000000000000835.9999999999 +836,900000000000000000000000000000000000000000000000000000000000000836.9999999999 +837,900000000000000000000000000000000000000000000000000000000000000837.9999999999 +838,900000000000000000000000000000000000000000000000000000000000000838.9999999999 +839,900000000000000000000000000000000000000000000000000000000000000839.9999999999 +840,900000000000000000000000000000000000000000000000000000000000000840.9999999999 +841,900000000000000000000000000000000000000000000000000000000000000841.9999999999 +842,900000000000000000000000000000000000000000000000000000000000000842.9999999999 +843,900000000000000000000000000000000000000000000000000000000000000843.9999999999 +844,900000000000000000000000000000000000000000000000000000000000000844.9999999999 +845,900000000000000000000000000000000000000000000000000000000000000845.9999999999 +846,900000000000000000000000000000000000000000000000000000000000000846.9999999999 +847,900000000000000000000000000000000000000000000000000000000000000847.9999999999 +848,900000000000000000000000000000000000000000000000000000000000000848.9999999999 +849,900000000000000000000000000000000000000000000000000000000000000849.9999999999 +850,900000000000000000000000000000000000000000000000000000000000000850.9999999999 +851,900000000000000000000000000000000000000000000000000000000000000851.9999999999 +852,900000000000000000000000000000000000000000000000000000000000000852.9999999999 +853,900000000000000000000000000000000000000000000000000000000000000853.9999999999 +854,900000000000000000000000000000000000000000000000000000000000000854.9999999999 +855,900000000000000000000000000000000000000000000000000000000000000855.9999999999 +856,900000000000000000000000000000000000000000000000000000000000000856.9999999999 +857,900000000000000000000000000000000000000000000000000000000000000857.9999999999 +858,900000000000000000000000000000000000000000000000000000000000000858.9999999999 +859,900000000000000000000000000000000000000000000000000000000000000859.9999999999 +860,900000000000000000000000000000000000000000000000000000000000000860.9999999999 +861,900000000000000000000000000000000000000000000000000000000000000861.9999999999 +862,900000000000000000000000000000000000000000000000000000000000000862.9999999999 +863,900000000000000000000000000000000000000000000000000000000000000863.9999999999 +864,900000000000000000000000000000000000000000000000000000000000000864.9999999999 +865,900000000000000000000000000000000000000000000000000000000000000865.9999999999 +866,900000000000000000000000000000000000000000000000000000000000000866.9999999999 +867,900000000000000000000000000000000000000000000000000000000000000867.9999999999 +868,900000000000000000000000000000000000000000000000000000000000000868.9999999999 +869,900000000000000000000000000000000000000000000000000000000000000869.9999999999 +870,900000000000000000000000000000000000000000000000000000000000000870.9999999999 +871,900000000000000000000000000000000000000000000000000000000000000871.9999999999 +872,900000000000000000000000000000000000000000000000000000000000000872.9999999999 +873,900000000000000000000000000000000000000000000000000000000000000873.9999999999 +874,900000000000000000000000000000000000000000000000000000000000000874.9999999999 +875,900000000000000000000000000000000000000000000000000000000000000875.9999999999 +876,900000000000000000000000000000000000000000000000000000000000000876.9999999999 +877,900000000000000000000000000000000000000000000000000000000000000877.9999999999 +878,900000000000000000000000000000000000000000000000000000000000000878.9999999999 +879,900000000000000000000000000000000000000000000000000000000000000879.9999999999 +880,900000000000000000000000000000000000000000000000000000000000000880.9999999999 +881,900000000000000000000000000000000000000000000000000000000000000881.9999999999 +882,900000000000000000000000000000000000000000000000000000000000000882.9999999999 +883,900000000000000000000000000000000000000000000000000000000000000883.9999999999 +884,900000000000000000000000000000000000000000000000000000000000000884.9999999999 +885,900000000000000000000000000000000000000000000000000000000000000885.9999999999 +886,900000000000000000000000000000000000000000000000000000000000000886.9999999999 +887,900000000000000000000000000000000000000000000000000000000000000887.9999999999 +888,900000000000000000000000000000000000000000000000000000000000000888.9999999999 +889,900000000000000000000000000000000000000000000000000000000000000889.9999999999 +890,900000000000000000000000000000000000000000000000000000000000000890.9999999999 +891,900000000000000000000000000000000000000000000000000000000000000891.9999999999 +892,900000000000000000000000000000000000000000000000000000000000000892.9999999999 +893,900000000000000000000000000000000000000000000000000000000000000893.9999999999 +894,900000000000000000000000000000000000000000000000000000000000000894.9999999999 +895,900000000000000000000000000000000000000000000000000000000000000895.9999999999 +896,900000000000000000000000000000000000000000000000000000000000000896.9999999999 +897,900000000000000000000000000000000000000000000000000000000000000897.9999999999 +898,900000000000000000000000000000000000000000000000000000000000000898.9999999999 +899,900000000000000000000000000000000000000000000000000000000000000899.9999999999 +900,900000000000000000000000000000000000000000000000000000000000000900.9999999999 +901,900000000000000000000000000000000000000000000000000000000000000901.9999999999 +902,900000000000000000000000000000000000000000000000000000000000000902.9999999999 +903,900000000000000000000000000000000000000000000000000000000000000903.9999999999 +904,900000000000000000000000000000000000000000000000000000000000000904.9999999999 +905,900000000000000000000000000000000000000000000000000000000000000905.9999999999 +906,900000000000000000000000000000000000000000000000000000000000000906.9999999999 +907,900000000000000000000000000000000000000000000000000000000000000907.9999999999 +908,900000000000000000000000000000000000000000000000000000000000000908.9999999999 +909,900000000000000000000000000000000000000000000000000000000000000909.9999999999 +910,900000000000000000000000000000000000000000000000000000000000000910.9999999999 +911,900000000000000000000000000000000000000000000000000000000000000911.9999999999 +912,900000000000000000000000000000000000000000000000000000000000000912.9999999999 +913,900000000000000000000000000000000000000000000000000000000000000913.9999999999 +914,900000000000000000000000000000000000000000000000000000000000000914.9999999999 +915,900000000000000000000000000000000000000000000000000000000000000915.9999999999 +916,900000000000000000000000000000000000000000000000000000000000000916.9999999999 +917,900000000000000000000000000000000000000000000000000000000000000917.9999999999 +918,900000000000000000000000000000000000000000000000000000000000000918.9999999999 +919,900000000000000000000000000000000000000000000000000000000000000919.9999999999 +920,900000000000000000000000000000000000000000000000000000000000000920.9999999999 +921,900000000000000000000000000000000000000000000000000000000000000921.9999999999 +922,900000000000000000000000000000000000000000000000000000000000000922.9999999999 +923,900000000000000000000000000000000000000000000000000000000000000923.9999999999 +924,900000000000000000000000000000000000000000000000000000000000000924.9999999999 +925,900000000000000000000000000000000000000000000000000000000000000925.9999999999 +926,900000000000000000000000000000000000000000000000000000000000000926.9999999999 +927,900000000000000000000000000000000000000000000000000000000000000927.9999999999 +928,900000000000000000000000000000000000000000000000000000000000000928.9999999999 +929,900000000000000000000000000000000000000000000000000000000000000929.9999999999 +930,900000000000000000000000000000000000000000000000000000000000000930.9999999999 +931,900000000000000000000000000000000000000000000000000000000000000931.9999999999 +932,900000000000000000000000000000000000000000000000000000000000000932.9999999999 +933,900000000000000000000000000000000000000000000000000000000000000933.9999999999 +934,900000000000000000000000000000000000000000000000000000000000000934.9999999999 +935,900000000000000000000000000000000000000000000000000000000000000935.9999999999 +936,900000000000000000000000000000000000000000000000000000000000000936.9999999999 +937,900000000000000000000000000000000000000000000000000000000000000937.9999999999 +938,900000000000000000000000000000000000000000000000000000000000000938.9999999999 +939,900000000000000000000000000000000000000000000000000000000000000939.9999999999 +940,900000000000000000000000000000000000000000000000000000000000000940.9999999999 +941,900000000000000000000000000000000000000000000000000000000000000941.9999999999 +942,900000000000000000000000000000000000000000000000000000000000000942.9999999999 +943,900000000000000000000000000000000000000000000000000000000000000943.9999999999 +944,900000000000000000000000000000000000000000000000000000000000000944.9999999999 +945,900000000000000000000000000000000000000000000000000000000000000945.9999999999 +946,900000000000000000000000000000000000000000000000000000000000000946.9999999999 +947,900000000000000000000000000000000000000000000000000000000000000947.9999999999 +948,900000000000000000000000000000000000000000000000000000000000000948.9999999999 +949,900000000000000000000000000000000000000000000000000000000000000949.9999999999 +950,900000000000000000000000000000000000000000000000000000000000000950.9999999999 +951,900000000000000000000000000000000000000000000000000000000000000951.9999999999 +952,900000000000000000000000000000000000000000000000000000000000000952.9999999999 +953,900000000000000000000000000000000000000000000000000000000000000953.9999999999 +954,900000000000000000000000000000000000000000000000000000000000000954.9999999999 +955,900000000000000000000000000000000000000000000000000000000000000955.9999999999 +956,900000000000000000000000000000000000000000000000000000000000000956.9999999999 +957,900000000000000000000000000000000000000000000000000000000000000957.9999999999 +958,900000000000000000000000000000000000000000000000000000000000000958.9999999999 +959,900000000000000000000000000000000000000000000000000000000000000959.9999999999 +960,900000000000000000000000000000000000000000000000000000000000000960.9999999999 +961,900000000000000000000000000000000000000000000000000000000000000961.9999999999 +962,900000000000000000000000000000000000000000000000000000000000000962.9999999999 +963,900000000000000000000000000000000000000000000000000000000000000963.9999999999 +964,900000000000000000000000000000000000000000000000000000000000000964.9999999999 +965,900000000000000000000000000000000000000000000000000000000000000965.9999999999 +966,900000000000000000000000000000000000000000000000000000000000000966.9999999999 +967,900000000000000000000000000000000000000000000000000000000000000967.9999999999 +968,900000000000000000000000000000000000000000000000000000000000000968.9999999999 +969,900000000000000000000000000000000000000000000000000000000000000969.9999999999 +970,900000000000000000000000000000000000000000000000000000000000000970.9999999999 +971,900000000000000000000000000000000000000000000000000000000000000971.9999999999 +972,900000000000000000000000000000000000000000000000000000000000000972.9999999999 +973,900000000000000000000000000000000000000000000000000000000000000973.9999999999 +974,900000000000000000000000000000000000000000000000000000000000000974.9999999999 +975,900000000000000000000000000000000000000000000000000000000000000975.9999999999 +976,900000000000000000000000000000000000000000000000000000000000000976.9999999999 +977,900000000000000000000000000000000000000000000000000000000000000977.9999999999 +978,900000000000000000000000000000000000000000000000000000000000000978.9999999999 +979,900000000000000000000000000000000000000000000000000000000000000979.9999999999 +980,900000000000000000000000000000000000000000000000000000000000000980.9999999999 +981,900000000000000000000000000000000000000000000000000000000000000981.9999999999 +982,900000000000000000000000000000000000000000000000000000000000000982.9999999999 +983,900000000000000000000000000000000000000000000000000000000000000983.9999999999 +984,900000000000000000000000000000000000000000000000000000000000000984.9999999999 +985,900000000000000000000000000000000000000000000000000000000000000985.9999999999 +986,900000000000000000000000000000000000000000000000000000000000000986.9999999999 +987,900000000000000000000000000000000000000000000000000000000000000987.9999999999 +988,900000000000000000000000000000000000000000000000000000000000000988.9999999999 +989,900000000000000000000000000000000000000000000000000000000000000989.9999999999 +990,900000000000000000000000000000000000000000000000000000000000000990.9999999999 +991,900000000000000000000000000000000000000000000000000000000000000991.9999999999 +992,900000000000000000000000000000000000000000000000000000000000000992.9999999999 +993,900000000000000000000000000000000000000000000000000000000000000993.9999999999 +994,900000000000000000000000000000000000000000000000000000000000000994.9999999999 +995,900000000000000000000000000000000000000000000000000000000000000995.9999999999 +996,900000000000000000000000000000000000000000000000000000000000000996.9999999999 +997,900000000000000000000000000000000000000000000000000000000000000997.9999999999 +998,900000000000000000000000000000000000000000000000000000000000000998.9999999999 +999,900000000000000000000000000000000000000000000000000000000000000999.9999999999 +1000,900000000000000000000000000000000000000000000000000000000000001000.9999999999 +1001,900000000000000000000000000000000000000000000000000000000000001001.9999999999 +1002,900000000000000000000000000000000000000000000000000000000000001002.9999999999 +1003,900000000000000000000000000000000000000000000000000000000000001003.9999999999 +1004,900000000000000000000000000000000000000000000000000000000000001004.9999999999 +1005,900000000000000000000000000000000000000000000000000000000000001005.9999999999 +1006,900000000000000000000000000000000000000000000000000000000000001006.9999999999 +1007,900000000000000000000000000000000000000000000000000000000000001007.9999999999 +1008,900000000000000000000000000000000000000000000000000000000000001008.9999999999 +1009,900000000000000000000000000000000000000000000000000000000000001009.9999999999 +1010,900000000000000000000000000000000000000000000000000000000000001010.9999999999 +1011,900000000000000000000000000000000000000000000000000000000000001011.9999999999 +1012,900000000000000000000000000000000000000000000000000000000000001012.9999999999 +1013,900000000000000000000000000000000000000000000000000000000000001013.9999999999 +1014,900000000000000000000000000000000000000000000000000000000000001014.9999999999 +1015,900000000000000000000000000000000000000000000000000000000000001015.9999999999 +1016,900000000000000000000000000000000000000000000000000000000000001016.9999999999 +1017,900000000000000000000000000000000000000000000000000000000000001017.9999999999 +1018,900000000000000000000000000000000000000000000000000000000000001018.9999999999 +1019,900000000000000000000000000000000000000000000000000000000000001019.9999999999 +1020,900000000000000000000000000000000000000000000000000000000000001020.9999999999 +1021,900000000000000000000000000000000000000000000000000000000000001021.9999999999 +1022,900000000000000000000000000000000000000000000000000000000000001022.9999999999 +1023,900000000000000000000000000000000000000000000000000000000000001023.9999999999 +1024,900000000000000000000000000000000000000000000000000000000000001024.9999999999 +1025,900000000000000000000000000000000000000000000000000000000000001025.9999999999 +1026,900000000000000000000000000000000000000000000000000000000000001026.9999999999 +1027,900000000000000000000000000000000000000000000000000000000000001027.9999999999 +1028,900000000000000000000000000000000000000000000000000000000000001028.9999999999 +1029,900000000000000000000000000000000000000000000000000000000000001029.9999999999 +1030,900000000000000000000000000000000000000000000000000000000000001030.9999999999 +1031,900000000000000000000000000000000000000000000000000000000000001031.9999999999 +1032,900000000000000000000000000000000000000000000000000000000000001032.9999999999 +1033,900000000000000000000000000000000000000000000000000000000000001033.9999999999 +1034,900000000000000000000000000000000000000000000000000000000000001034.9999999999 +1035,900000000000000000000000000000000000000000000000000000000000001035.9999999999 +1036,900000000000000000000000000000000000000000000000000000000000001036.9999999999 +1037,900000000000000000000000000000000000000000000000000000000000001037.9999999999 +1038,900000000000000000000000000000000000000000000000000000000000001038.9999999999 +1039,900000000000000000000000000000000000000000000000000000000000001039.9999999999 +1040,900000000000000000000000000000000000000000000000000000000000001040.9999999999 +1041,900000000000000000000000000000000000000000000000000000000000001041.9999999999 +1042,900000000000000000000000000000000000000000000000000000000000001042.9999999999 +1043,900000000000000000000000000000000000000000000000000000000000001043.9999999999 +1044,900000000000000000000000000000000000000000000000000000000000001044.9999999999 +1045,900000000000000000000000000000000000000000000000000000000000001045.9999999999 +1046,900000000000000000000000000000000000000000000000000000000000001046.9999999999 +1047,900000000000000000000000000000000000000000000000000000000000001047.9999999999 +1048,900000000000000000000000000000000000000000000000000000000000001048.9999999999 +1049,900000000000000000000000000000000000000000000000000000000000001049.9999999999 +1050,900000000000000000000000000000000000000000000000000000000000001050.9999999999 +1051,900000000000000000000000000000000000000000000000000000000000001051.9999999999 +1052,900000000000000000000000000000000000000000000000000000000000001052.9999999999 +1053,900000000000000000000000000000000000000000000000000000000000001053.9999999999 +1054,900000000000000000000000000000000000000000000000000000000000001054.9999999999 +1055,900000000000000000000000000000000000000000000000000000000000001055.9999999999 +1056,900000000000000000000000000000000000000000000000000000000000001056.9999999999 +1057,900000000000000000000000000000000000000000000000000000000000001057.9999999999 +1058,900000000000000000000000000000000000000000000000000000000000001058.9999999999 +1059,900000000000000000000000000000000000000000000000000000000000001059.9999999999 +1060,900000000000000000000000000000000000000000000000000000000000001060.9999999999 +1061,900000000000000000000000000000000000000000000000000000000000001061.9999999999 +1062,900000000000000000000000000000000000000000000000000000000000001062.9999999999 +1063,900000000000000000000000000000000000000000000000000000000000001063.9999999999 +1064,900000000000000000000000000000000000000000000000000000000000001064.9999999999 +1065,900000000000000000000000000000000000000000000000000000000000001065.9999999999 +1066,900000000000000000000000000000000000000000000000000000000000001066.9999999999 +1067,900000000000000000000000000000000000000000000000000000000000001067.9999999999 +1068,900000000000000000000000000000000000000000000000000000000000001068.9999999999 +1069,900000000000000000000000000000000000000000000000000000000000001069.9999999999 +1070,900000000000000000000000000000000000000000000000000000000000001070.9999999999 +1071,900000000000000000000000000000000000000000000000000000000000001071.9999999999 +1072,900000000000000000000000000000000000000000000000000000000000001072.9999999999 +1073,900000000000000000000000000000000000000000000000000000000000001073.9999999999 +1074,900000000000000000000000000000000000000000000000000000000000001074.9999999999 +1075,900000000000000000000000000000000000000000000000000000000000001075.9999999999 +1076,900000000000000000000000000000000000000000000000000000000000001076.9999999999 +1077,900000000000000000000000000000000000000000000000000000000000001077.9999999999 +1078,900000000000000000000000000000000000000000000000000000000000001078.9999999999 +1079,900000000000000000000000000000000000000000000000000000000000001079.9999999999 +1080,900000000000000000000000000000000000000000000000000000000000001080.9999999999 +1081,900000000000000000000000000000000000000000000000000000000000001081.9999999999 +1082,900000000000000000000000000000000000000000000000000000000000001082.9999999999 +1083,900000000000000000000000000000000000000000000000000000000000001083.9999999999 +1084,900000000000000000000000000000000000000000000000000000000000001084.9999999999 +1085,900000000000000000000000000000000000000000000000000000000000001085.9999999999 +1086,900000000000000000000000000000000000000000000000000000000000001086.9999999999 +1087,900000000000000000000000000000000000000000000000000000000000001087.9999999999 +1088,900000000000000000000000000000000000000000000000000000000000001088.9999999999 +1089,900000000000000000000000000000000000000000000000000000000000001089.9999999999 +1090,900000000000000000000000000000000000000000000000000000000000001090.9999999999 +1091,900000000000000000000000000000000000000000000000000000000000001091.9999999999 +1092,900000000000000000000000000000000000000000000000000000000000001092.9999999999 +1093,900000000000000000000000000000000000000000000000000000000000001093.9999999999 +1094,900000000000000000000000000000000000000000000000000000000000001094.9999999999 +1095,900000000000000000000000000000000000000000000000000000000000001095.9999999999 +1096,900000000000000000000000000000000000000000000000000000000000001096.9999999999 +1097,900000000000000000000000000000000000000000000000000000000000001097.9999999999 +1098,900000000000000000000000000000000000000000000000000000000000001098.9999999999 +1099,900000000000000000000000000000000000000000000000000000000000001099.9999999999 +1100,900000000000000000000000000000000000000000000000000000000000001100.9999999999 +1101,900000000000000000000000000000000000000000000000000000000000001101.9999999999 +1102,900000000000000000000000000000000000000000000000000000000000001102.9999999999 +1103,900000000000000000000000000000000000000000000000000000000000001103.9999999999 +1104,900000000000000000000000000000000000000000000000000000000000001104.9999999999 +1105,900000000000000000000000000000000000000000000000000000000000001105.9999999999 +1106,900000000000000000000000000000000000000000000000000000000000001106.9999999999 +1107,900000000000000000000000000000000000000000000000000000000000001107.9999999999 +1108,900000000000000000000000000000000000000000000000000000000000001108.9999999999 +1109,900000000000000000000000000000000000000000000000000000000000001109.9999999999 +1110,900000000000000000000000000000000000000000000000000000000000001110.9999999999 +1111,900000000000000000000000000000000000000000000000000000000000001111.9999999999 +1112,900000000000000000000000000000000000000000000000000000000000001112.9999999999 +1113,900000000000000000000000000000000000000000000000000000000000001113.9999999999 +1114,900000000000000000000000000000000000000000000000000000000000001114.9999999999 +1115,900000000000000000000000000000000000000000000000000000000000001115.9999999999 +1116,900000000000000000000000000000000000000000000000000000000000001116.9999999999 +1117,900000000000000000000000000000000000000000000000000000000000001117.9999999999 +1118,900000000000000000000000000000000000000000000000000000000000001118.9999999999 +1119,900000000000000000000000000000000000000000000000000000000000001119.9999999999 +1120,900000000000000000000000000000000000000000000000000000000000001120.9999999999 +1121,900000000000000000000000000000000000000000000000000000000000001121.9999999999 +1122,900000000000000000000000000000000000000000000000000000000000001122.9999999999 +1123,900000000000000000000000000000000000000000000000000000000000001123.9999999999 +1124,900000000000000000000000000000000000000000000000000000000000001124.9999999999 +1125,900000000000000000000000000000000000000000000000000000000000001125.9999999999 +1126,900000000000000000000000000000000000000000000000000000000000001126.9999999999 +1127,900000000000000000000000000000000000000000000000000000000000001127.9999999999 +1128,900000000000000000000000000000000000000000000000000000000000001128.9999999999 +1129,900000000000000000000000000000000000000000000000000000000000001129.9999999999 +1130,900000000000000000000000000000000000000000000000000000000000001130.9999999999 +1131,900000000000000000000000000000000000000000000000000000000000001131.9999999999 +1132,900000000000000000000000000000000000000000000000000000000000001132.9999999999 +1133,900000000000000000000000000000000000000000000000000000000000001133.9999999999 +1134,900000000000000000000000000000000000000000000000000000000000001134.9999999999 +1135,900000000000000000000000000000000000000000000000000000000000001135.9999999999 +1136,900000000000000000000000000000000000000000000000000000000000001136.9999999999 +1137,900000000000000000000000000000000000000000000000000000000000001137.9999999999 +1138,900000000000000000000000000000000000000000000000000000000000001138.9999999999 +1139,900000000000000000000000000000000000000000000000000000000000001139.9999999999 +1140,900000000000000000000000000000000000000000000000000000000000001140.9999999999 +1141,900000000000000000000000000000000000000000000000000000000000001141.9999999999 +1142,900000000000000000000000000000000000000000000000000000000000001142.9999999999 +1143,900000000000000000000000000000000000000000000000000000000000001143.9999999999 +1144,900000000000000000000000000000000000000000000000000000000000001144.9999999999 +1145,900000000000000000000000000000000000000000000000000000000000001145.9999999999 +1146,900000000000000000000000000000000000000000000000000000000000001146.9999999999 +1147,900000000000000000000000000000000000000000000000000000000000001147.9999999999 +1148,900000000000000000000000000000000000000000000000000000000000001148.9999999999 +1149,900000000000000000000000000000000000000000000000000000000000001149.9999999999 +1150,900000000000000000000000000000000000000000000000000000000000001150.9999999999 +1151,900000000000000000000000000000000000000000000000000000000000001151.9999999999 +1152,900000000000000000000000000000000000000000000000000000000000001152.9999999999 +1153,900000000000000000000000000000000000000000000000000000000000001153.9999999999 +1154,900000000000000000000000000000000000000000000000000000000000001154.9999999999 +1155,900000000000000000000000000000000000000000000000000000000000001155.9999999999 +1156,900000000000000000000000000000000000000000000000000000000000001156.9999999999 +1157,900000000000000000000000000000000000000000000000000000000000001157.9999999999 +1158,900000000000000000000000000000000000000000000000000000000000001158.9999999999 +1159,900000000000000000000000000000000000000000000000000000000000001159.9999999999 +1160,900000000000000000000000000000000000000000000000000000000000001160.9999999999 +1161,900000000000000000000000000000000000000000000000000000000000001161.9999999999 +1162,900000000000000000000000000000000000000000000000000000000000001162.9999999999 +1163,900000000000000000000000000000000000000000000000000000000000001163.9999999999 +1164,900000000000000000000000000000000000000000000000000000000000001164.9999999999 +1165,900000000000000000000000000000000000000000000000000000000000001165.9999999999 +1166,900000000000000000000000000000000000000000000000000000000000001166.9999999999 +1167,900000000000000000000000000000000000000000000000000000000000001167.9999999999 +1168,900000000000000000000000000000000000000000000000000000000000001168.9999999999 +1169,900000000000000000000000000000000000000000000000000000000000001169.9999999999 +1170,900000000000000000000000000000000000000000000000000000000000001170.9999999999 +1171,900000000000000000000000000000000000000000000000000000000000001171.9999999999 +1172,900000000000000000000000000000000000000000000000000000000000001172.9999999999 +1173,900000000000000000000000000000000000000000000000000000000000001173.9999999999 +1174,900000000000000000000000000000000000000000000000000000000000001174.9999999999 +1175,900000000000000000000000000000000000000000000000000000000000001175.9999999999 +1176,900000000000000000000000000000000000000000000000000000000000001176.9999999999 +1177,900000000000000000000000000000000000000000000000000000000000001177.9999999999 +1178,900000000000000000000000000000000000000000000000000000000000001178.9999999999 +1179,900000000000000000000000000000000000000000000000000000000000001179.9999999999 +1180,900000000000000000000000000000000000000000000000000000000000001180.9999999999 +1181,900000000000000000000000000000000000000000000000000000000000001181.9999999999 +1182,900000000000000000000000000000000000000000000000000000000000001182.9999999999 +1183,900000000000000000000000000000000000000000000000000000000000001183.9999999999 +1184,900000000000000000000000000000000000000000000000000000000000001184.9999999999 +1185,900000000000000000000000000000000000000000000000000000000000001185.9999999999 +1186,900000000000000000000000000000000000000000000000000000000000001186.9999999999 +1187,900000000000000000000000000000000000000000000000000000000000001187.9999999999 +1188,900000000000000000000000000000000000000000000000000000000000001188.9999999999 +1189,900000000000000000000000000000000000000000000000000000000000001189.9999999999 +1190,900000000000000000000000000000000000000000000000000000000000001190.9999999999 +1191,900000000000000000000000000000000000000000000000000000000000001191.9999999999 +1192,900000000000000000000000000000000000000000000000000000000000001192.9999999999 +1193,900000000000000000000000000000000000000000000000000000000000001193.9999999999 +1194,900000000000000000000000000000000000000000000000000000000000001194.9999999999 +1195,900000000000000000000000000000000000000000000000000000000000001195.9999999999 +1196,900000000000000000000000000000000000000000000000000000000000001196.9999999999 +1197,900000000000000000000000000000000000000000000000000000000000001197.9999999999 +1198,900000000000000000000000000000000000000000000000000000000000001198.9999999999 +1199,900000000000000000000000000000000000000000000000000000000000001199.9999999999 +1200,900000000000000000000000000000000000000000000000000000000000001200.9999999999 +1201,900000000000000000000000000000000000000000000000000000000000001201.9999999999 +1202,900000000000000000000000000000000000000000000000000000000000001202.9999999999 +1203,900000000000000000000000000000000000000000000000000000000000001203.9999999999 +1204,900000000000000000000000000000000000000000000000000000000000001204.9999999999 +1205,900000000000000000000000000000000000000000000000000000000000001205.9999999999 +1206,900000000000000000000000000000000000000000000000000000000000001206.9999999999 +1207,900000000000000000000000000000000000000000000000000000000000001207.9999999999 +1208,900000000000000000000000000000000000000000000000000000000000001208.9999999999 +1209,900000000000000000000000000000000000000000000000000000000000001209.9999999999 +1210,900000000000000000000000000000000000000000000000000000000000001210.9999999999 +1211,900000000000000000000000000000000000000000000000000000000000001211.9999999999 +1212,900000000000000000000000000000000000000000000000000000000000001212.9999999999 +1213,900000000000000000000000000000000000000000000000000000000000001213.9999999999 +1214,900000000000000000000000000000000000000000000000000000000000001214.9999999999 +1215,900000000000000000000000000000000000000000000000000000000000001215.9999999999 +1216,900000000000000000000000000000000000000000000000000000000000001216.9999999999 +1217,900000000000000000000000000000000000000000000000000000000000001217.9999999999 +1218,900000000000000000000000000000000000000000000000000000000000001218.9999999999 +1219,900000000000000000000000000000000000000000000000000000000000001219.9999999999 +1220,900000000000000000000000000000000000000000000000000000000000001220.9999999999 +1221,900000000000000000000000000000000000000000000000000000000000001221.9999999999 +1222,900000000000000000000000000000000000000000000000000000000000001222.9999999999 +1223,900000000000000000000000000000000000000000000000000000000000001223.9999999999 +1224,900000000000000000000000000000000000000000000000000000000000001224.9999999999 +1225,900000000000000000000000000000000000000000000000000000000000001225.9999999999 +1226,900000000000000000000000000000000000000000000000000000000000001226.9999999999 +1227,900000000000000000000000000000000000000000000000000000000000001227.9999999999 +1228,900000000000000000000000000000000000000000000000000000000000001228.9999999999 +1229,900000000000000000000000000000000000000000000000000000000000001229.9999999999 +1230,900000000000000000000000000000000000000000000000000000000000001230.9999999999 +1231,900000000000000000000000000000000000000000000000000000000000001231.9999999999 +1232,900000000000000000000000000000000000000000000000000000000000001232.9999999999 +1233,900000000000000000000000000000000000000000000000000000000000001233.9999999999 +1234,900000000000000000000000000000000000000000000000000000000000001234.9999999999 +1235,900000000000000000000000000000000000000000000000000000000000001235.9999999999 +1236,900000000000000000000000000000000000000000000000000000000000001236.9999999999 +1237,900000000000000000000000000000000000000000000000000000000000001237.9999999999 +1238,900000000000000000000000000000000000000000000000000000000000001238.9999999999 +1239,900000000000000000000000000000000000000000000000000000000000001239.9999999999 +1240,900000000000000000000000000000000000000000000000000000000000001240.9999999999 +1241,900000000000000000000000000000000000000000000000000000000000001241.9999999999 +1242,900000000000000000000000000000000000000000000000000000000000001242.9999999999 +1243,900000000000000000000000000000000000000000000000000000000000001243.9999999999 +1244,900000000000000000000000000000000000000000000000000000000000001244.9999999999 +1245,900000000000000000000000000000000000000000000000000000000000001245.9999999999 +1246,900000000000000000000000000000000000000000000000000000000000001246.9999999999 +1247,900000000000000000000000000000000000000000000000000000000000001247.9999999999 +1248,900000000000000000000000000000000000000000000000000000000000001248.9999999999 +1249,900000000000000000000000000000000000000000000000000000000000001249.9999999999 +1250,900000000000000000000000000000000000000000000000000000000000001250.9999999999 +1251,900000000000000000000000000000000000000000000000000000000000001251.9999999999 +1252,900000000000000000000000000000000000000000000000000000000000001252.9999999999 +1253,900000000000000000000000000000000000000000000000000000000000001253.9999999999 +1254,900000000000000000000000000000000000000000000000000000000000001254.9999999999 +1255,900000000000000000000000000000000000000000000000000000000000001255.9999999999 +1256,900000000000000000000000000000000000000000000000000000000000001256.9999999999 +1257,900000000000000000000000000000000000000000000000000000000000001257.9999999999 +1258,900000000000000000000000000000000000000000000000000000000000001258.9999999999 +1259,900000000000000000000000000000000000000000000000000000000000001259.9999999999 +1260,900000000000000000000000000000000000000000000000000000000000001260.9999999999 +1261,900000000000000000000000000000000000000000000000000000000000001261.9999999999 +1262,900000000000000000000000000000000000000000000000000000000000001262.9999999999 +1263,900000000000000000000000000000000000000000000000000000000000001263.9999999999 +1264,900000000000000000000000000000000000000000000000000000000000001264.9999999999 +1265,900000000000000000000000000000000000000000000000000000000000001265.9999999999 +1266,900000000000000000000000000000000000000000000000000000000000001266.9999999999 +1267,900000000000000000000000000000000000000000000000000000000000001267.9999999999 +1268,900000000000000000000000000000000000000000000000000000000000001268.9999999999 +1269,900000000000000000000000000000000000000000000000000000000000001269.9999999999 +1270,900000000000000000000000000000000000000000000000000000000000001270.9999999999 +1271,900000000000000000000000000000000000000000000000000000000000001271.9999999999 +1272,900000000000000000000000000000000000000000000000000000000000001272.9999999999 +1273,900000000000000000000000000000000000000000000000000000000000001273.9999999999 +1274,900000000000000000000000000000000000000000000000000000000000001274.9999999999 +1275,900000000000000000000000000000000000000000000000000000000000001275.9999999999 +1276,900000000000000000000000000000000000000000000000000000000000001276.9999999999 +1277,900000000000000000000000000000000000000000000000000000000000001277.9999999999 +1278,900000000000000000000000000000000000000000000000000000000000001278.9999999999 +1279,900000000000000000000000000000000000000000000000000000000000001279.9999999999 +1280,900000000000000000000000000000000000000000000000000000000000001280.9999999999 +1281,900000000000000000000000000000000000000000000000000000000000001281.9999999999 +1282,900000000000000000000000000000000000000000000000000000000000001282.9999999999 +1283,900000000000000000000000000000000000000000000000000000000000001283.9999999999 +1284,900000000000000000000000000000000000000000000000000000000000001284.9999999999 +1285,900000000000000000000000000000000000000000000000000000000000001285.9999999999 +1286,900000000000000000000000000000000000000000000000000000000000001286.9999999999 +1287,900000000000000000000000000000000000000000000000000000000000001287.9999999999 +1288,900000000000000000000000000000000000000000000000000000000000001288.9999999999 +1289,900000000000000000000000000000000000000000000000000000000000001289.9999999999 +1290,900000000000000000000000000000000000000000000000000000000000001290.9999999999 +1291,900000000000000000000000000000000000000000000000000000000000001291.9999999999 +1292,900000000000000000000000000000000000000000000000000000000000001292.9999999999 +1293,900000000000000000000000000000000000000000000000000000000000001293.9999999999 +1294,900000000000000000000000000000000000000000000000000000000000001294.9999999999 +1295,900000000000000000000000000000000000000000000000000000000000001295.9999999999 +1296,900000000000000000000000000000000000000000000000000000000000001296.9999999999 +1297,900000000000000000000000000000000000000000000000000000000000001297.9999999999 +1298,900000000000000000000000000000000000000000000000000000000000001298.9999999999 +1299,900000000000000000000000000000000000000000000000000000000000001299.9999999999 +1300,900000000000000000000000000000000000000000000000000000000000001300.9999999999 +1301,900000000000000000000000000000000000000000000000000000000000001301.9999999999 +1302,900000000000000000000000000000000000000000000000000000000000001302.9999999999 +1303,900000000000000000000000000000000000000000000000000000000000001303.9999999999 +1304,900000000000000000000000000000000000000000000000000000000000001304.9999999999 +1305,900000000000000000000000000000000000000000000000000000000000001305.9999999999 +1306,900000000000000000000000000000000000000000000000000000000000001306.9999999999 +1307,900000000000000000000000000000000000000000000000000000000000001307.9999999999 +1308,900000000000000000000000000000000000000000000000000000000000001308.9999999999 +1309,900000000000000000000000000000000000000000000000000000000000001309.9999999999 +1310,900000000000000000000000000000000000000000000000000000000000001310.9999999999 +1311,900000000000000000000000000000000000000000000000000000000000001311.9999999999 +1312,900000000000000000000000000000000000000000000000000000000000001312.9999999999 +1313,900000000000000000000000000000000000000000000000000000000000001313.9999999999 +1314,900000000000000000000000000000000000000000000000000000000000001314.9999999999 +1315,900000000000000000000000000000000000000000000000000000000000001315.9999999999 +1316,900000000000000000000000000000000000000000000000000000000000001316.9999999999 +1317,900000000000000000000000000000000000000000000000000000000000001317.9999999999 +1318,900000000000000000000000000000000000000000000000000000000000001318.9999999999 +1319,900000000000000000000000000000000000000000000000000000000000001319.9999999999 +1320,900000000000000000000000000000000000000000000000000000000000001320.9999999999 +1321,900000000000000000000000000000000000000000000000000000000000001321.9999999999 +1322,900000000000000000000000000000000000000000000000000000000000001322.9999999999 +1323,900000000000000000000000000000000000000000000000000000000000001323.9999999999 +1324,900000000000000000000000000000000000000000000000000000000000001324.9999999999 +1325,900000000000000000000000000000000000000000000000000000000000001325.9999999999 +1326,900000000000000000000000000000000000000000000000000000000000001326.9999999999 +1327,900000000000000000000000000000000000000000000000000000000000001327.9999999999 +1328,900000000000000000000000000000000000000000000000000000000000001328.9999999999 +1329,900000000000000000000000000000000000000000000000000000000000001329.9999999999 +1330,900000000000000000000000000000000000000000000000000000000000001330.9999999999 +1331,900000000000000000000000000000000000000000000000000000000000001331.9999999999 +1332,900000000000000000000000000000000000000000000000000000000000001332.9999999999 +1333,900000000000000000000000000000000000000000000000000000000000001333.9999999999 +1334,900000000000000000000000000000000000000000000000000000000000001334.9999999999 +1335,900000000000000000000000000000000000000000000000000000000000001335.9999999999 +1336,900000000000000000000000000000000000000000000000000000000000001336.9999999999 +1337,900000000000000000000000000000000000000000000000000000000000001337.9999999999 +1338,900000000000000000000000000000000000000000000000000000000000001338.9999999999 +1339,900000000000000000000000000000000000000000000000000000000000001339.9999999999 +1340,900000000000000000000000000000000000000000000000000000000000001340.9999999999 +1341,900000000000000000000000000000000000000000000000000000000000001341.9999999999 +1342,900000000000000000000000000000000000000000000000000000000000001342.9999999999 +1343,900000000000000000000000000000000000000000000000000000000000001343.9999999999 +1344,900000000000000000000000000000000000000000000000000000000000001344.9999999999 +1345,900000000000000000000000000000000000000000000000000000000000001345.9999999999 +1346,900000000000000000000000000000000000000000000000000000000000001346.9999999999 +1347,900000000000000000000000000000000000000000000000000000000000001347.9999999999 +1348,900000000000000000000000000000000000000000000000000000000000001348.9999999999 +1349,900000000000000000000000000000000000000000000000000000000000001349.9999999999 +1350,900000000000000000000000000000000000000000000000000000000000001350.9999999999 +1351,900000000000000000000000000000000000000000000000000000000000001351.9999999999 +1352,900000000000000000000000000000000000000000000000000000000000001352.9999999999 +1353,900000000000000000000000000000000000000000000000000000000000001353.9999999999 +1354,900000000000000000000000000000000000000000000000000000000000001354.9999999999 +1355,900000000000000000000000000000000000000000000000000000000000001355.9999999999 +1356,900000000000000000000000000000000000000000000000000000000000001356.9999999999 +1357,900000000000000000000000000000000000000000000000000000000000001357.9999999999 +1358,900000000000000000000000000000000000000000000000000000000000001358.9999999999 +1359,900000000000000000000000000000000000000000000000000000000000001359.9999999999 +1360,900000000000000000000000000000000000000000000000000000000000001360.9999999999 +1361,900000000000000000000000000000000000000000000000000000000000001361.9999999999 +1362,900000000000000000000000000000000000000000000000000000000000001362.9999999999 +1363,900000000000000000000000000000000000000000000000000000000000001363.9999999999 +1364,900000000000000000000000000000000000000000000000000000000000001364.9999999999 +1365,900000000000000000000000000000000000000000000000000000000000001365.9999999999 +1366,900000000000000000000000000000000000000000000000000000000000001366.9999999999 +1367,900000000000000000000000000000000000000000000000000000000000001367.9999999999 +1368,900000000000000000000000000000000000000000000000000000000000001368.9999999999 +1369,900000000000000000000000000000000000000000000000000000000000001369.9999999999 +1370,900000000000000000000000000000000000000000000000000000000000001370.9999999999 +1371,900000000000000000000000000000000000000000000000000000000000001371.9999999999 +1372,900000000000000000000000000000000000000000000000000000000000001372.9999999999 +1373,900000000000000000000000000000000000000000000000000000000000001373.9999999999 +1374,900000000000000000000000000000000000000000000000000000000000001374.9999999999 +1375,900000000000000000000000000000000000000000000000000000000000001375.9999999999 +1376,900000000000000000000000000000000000000000000000000000000000001376.9999999999 +1377,900000000000000000000000000000000000000000000000000000000000001377.9999999999 +1378,900000000000000000000000000000000000000000000000000000000000001378.9999999999 +1379,900000000000000000000000000000000000000000000000000000000000001379.9999999999 +1380,900000000000000000000000000000000000000000000000000000000000001380.9999999999 +1381,900000000000000000000000000000000000000000000000000000000000001381.9999999999 +1382,900000000000000000000000000000000000000000000000000000000000001382.9999999999 +1383,900000000000000000000000000000000000000000000000000000000000001383.9999999999 +1384,900000000000000000000000000000000000000000000000000000000000001384.9999999999 +1385,900000000000000000000000000000000000000000000000000000000000001385.9999999999 +1386,900000000000000000000000000000000000000000000000000000000000001386.9999999999 +1387,900000000000000000000000000000000000000000000000000000000000001387.9999999999 +1388,900000000000000000000000000000000000000000000000000000000000001388.9999999999 +1389,900000000000000000000000000000000000000000000000000000000000001389.9999999999 +1390,900000000000000000000000000000000000000000000000000000000000001390.9999999999 +1391,900000000000000000000000000000000000000000000000000000000000001391.9999999999 +1392,900000000000000000000000000000000000000000000000000000000000001392.9999999999 +1393,900000000000000000000000000000000000000000000000000000000000001393.9999999999 +1394,900000000000000000000000000000000000000000000000000000000000001394.9999999999 +1395,900000000000000000000000000000000000000000000000000000000000001395.9999999999 +1396,900000000000000000000000000000000000000000000000000000000000001396.9999999999 +1397,900000000000000000000000000000000000000000000000000000000000001397.9999999999 +1398,900000000000000000000000000000000000000000000000000000000000001398.9999999999 +1399,900000000000000000000000000000000000000000000000000000000000001399.9999999999 +1400,900000000000000000000000000000000000000000000000000000000000001400.9999999999 +1401,900000000000000000000000000000000000000000000000000000000000001401.9999999999 +1402,900000000000000000000000000000000000000000000000000000000000001402.9999999999 +1403,900000000000000000000000000000000000000000000000000000000000001403.9999999999 +1404,900000000000000000000000000000000000000000000000000000000000001404.9999999999 +1405,900000000000000000000000000000000000000000000000000000000000001405.9999999999 +1406,900000000000000000000000000000000000000000000000000000000000001406.9999999999 +1407,900000000000000000000000000000000000000000000000000000000000001407.9999999999 +1408,900000000000000000000000000000000000000000000000000000000000001408.9999999999 +1409,900000000000000000000000000000000000000000000000000000000000001409.9999999999 +1410,900000000000000000000000000000000000000000000000000000000000001410.9999999999 +1411,900000000000000000000000000000000000000000000000000000000000001411.9999999999 +1412,900000000000000000000000000000000000000000000000000000000000001412.9999999999 +1413,900000000000000000000000000000000000000000000000000000000000001413.9999999999 +1414,900000000000000000000000000000000000000000000000000000000000001414.9999999999 +1415,900000000000000000000000000000000000000000000000000000000000001415.9999999999 +1416,900000000000000000000000000000000000000000000000000000000000001416.9999999999 +1417,900000000000000000000000000000000000000000000000000000000000001417.9999999999 +1418,900000000000000000000000000000000000000000000000000000000000001418.9999999999 +1419,900000000000000000000000000000000000000000000000000000000000001419.9999999999 +1420,900000000000000000000000000000000000000000000000000000000000001420.9999999999 +1421,900000000000000000000000000000000000000000000000000000000000001421.9999999999 +1422,900000000000000000000000000000000000000000000000000000000000001422.9999999999 +1423,900000000000000000000000000000000000000000000000000000000000001423.9999999999 +1424,900000000000000000000000000000000000000000000000000000000000001424.9999999999 +1425,900000000000000000000000000000000000000000000000000000000000001425.9999999999 +1426,900000000000000000000000000000000000000000000000000000000000001426.9999999999 +1427,900000000000000000000000000000000000000000000000000000000000001427.9999999999 +1428,900000000000000000000000000000000000000000000000000000000000001428.9999999999 +1429,900000000000000000000000000000000000000000000000000000000000001429.9999999999 +1430,900000000000000000000000000000000000000000000000000000000000001430.9999999999 +1431,900000000000000000000000000000000000000000000000000000000000001431.9999999999 +1432,900000000000000000000000000000000000000000000000000000000000001432.9999999999 +1433,900000000000000000000000000000000000000000000000000000000000001433.9999999999 +1434,900000000000000000000000000000000000000000000000000000000000001434.9999999999 +1435,900000000000000000000000000000000000000000000000000000000000001435.9999999999 +1436,900000000000000000000000000000000000000000000000000000000000001436.9999999999 +1437,900000000000000000000000000000000000000000000000000000000000001437.9999999999 +1438,900000000000000000000000000000000000000000000000000000000000001438.9999999999 +1439,900000000000000000000000000000000000000000000000000000000000001439.9999999999 +1440,900000000000000000000000000000000000000000000000000000000000001440.9999999999 +1441,900000000000000000000000000000000000000000000000000000000000001441.9999999999 +1442,900000000000000000000000000000000000000000000000000000000000001442.9999999999 +1443,900000000000000000000000000000000000000000000000000000000000001443.9999999999 +1444,900000000000000000000000000000000000000000000000000000000000001444.9999999999 +1445,900000000000000000000000000000000000000000000000000000000000001445.9999999999 +1446,900000000000000000000000000000000000000000000000000000000000001446.9999999999 +1447,900000000000000000000000000000000000000000000000000000000000001447.9999999999 +1448,900000000000000000000000000000000000000000000000000000000000001448.9999999999 +1449,900000000000000000000000000000000000000000000000000000000000001449.9999999999 +1450,900000000000000000000000000000000000000000000000000000000000001450.9999999999 +1451,900000000000000000000000000000000000000000000000000000000000001451.9999999999 +1452,900000000000000000000000000000000000000000000000000000000000001452.9999999999 +1453,900000000000000000000000000000000000000000000000000000000000001453.9999999999 +1454,900000000000000000000000000000000000000000000000000000000000001454.9999999999 +1455,900000000000000000000000000000000000000000000000000000000000001455.9999999999 +1456,900000000000000000000000000000000000000000000000000000000000001456.9999999999 +1457,900000000000000000000000000000000000000000000000000000000000001457.9999999999 +1458,900000000000000000000000000000000000000000000000000000000000001458.9999999999 +1459,900000000000000000000000000000000000000000000000000000000000001459.9999999999 +1460,900000000000000000000000000000000000000000000000000000000000001460.9999999999 +1461,900000000000000000000000000000000000000000000000000000000000001461.9999999999 +1462,900000000000000000000000000000000000000000000000000000000000001462.9999999999 +1463,900000000000000000000000000000000000000000000000000000000000001463.9999999999 +1464,900000000000000000000000000000000000000000000000000000000000001464.9999999999 +1465,900000000000000000000000000000000000000000000000000000000000001465.9999999999 +1466,900000000000000000000000000000000000000000000000000000000000001466.9999999999 +1467,900000000000000000000000000000000000000000000000000000000000001467.9999999999 +1468,900000000000000000000000000000000000000000000000000000000000001468.9999999999 +1469,900000000000000000000000000000000000000000000000000000000000001469.9999999999 +1470,900000000000000000000000000000000000000000000000000000000000001470.9999999999 +1471,900000000000000000000000000000000000000000000000000000000000001471.9999999999 +1472,900000000000000000000000000000000000000000000000000000000000001472.9999999999 +1473,900000000000000000000000000000000000000000000000000000000000001473.9999999999 +1474,900000000000000000000000000000000000000000000000000000000000001474.9999999999 +1475,900000000000000000000000000000000000000000000000000000000000001475.9999999999 +1476,900000000000000000000000000000000000000000000000000000000000001476.9999999999 +1477,900000000000000000000000000000000000000000000000000000000000001477.9999999999 +1478,900000000000000000000000000000000000000000000000000000000000001478.9999999999 +1479,900000000000000000000000000000000000000000000000000000000000001479.9999999999 +1480,900000000000000000000000000000000000000000000000000000000000001480.9999999999 +1481,900000000000000000000000000000000000000000000000000000000000001481.9999999999 +1482,900000000000000000000000000000000000000000000000000000000000001482.9999999999 +1483,900000000000000000000000000000000000000000000000000000000000001483.9999999999 +1484,900000000000000000000000000000000000000000000000000000000000001484.9999999999 +1485,900000000000000000000000000000000000000000000000000000000000001485.9999999999 +1486,900000000000000000000000000000000000000000000000000000000000001486.9999999999 +1487,900000000000000000000000000000000000000000000000000000000000001487.9999999999 +1488,900000000000000000000000000000000000000000000000000000000000001488.9999999999 +1489,900000000000000000000000000000000000000000000000000000000000001489.9999999999 +1490,900000000000000000000000000000000000000000000000000000000000001490.9999999999 +1491,900000000000000000000000000000000000000000000000000000000000001491.9999999999 +1492,900000000000000000000000000000000000000000000000000000000000001492.9999999999 +1493,900000000000000000000000000000000000000000000000000000000000001493.9999999999 +1494,900000000000000000000000000000000000000000000000000000000000001494.9999999999 +1495,900000000000000000000000000000000000000000000000000000000000001495.9999999999 +1496,900000000000000000000000000000000000000000000000000000000000001496.9999999999 +1497,900000000000000000000000000000000000000000000000000000000000001497.9999999999 +1498,900000000000000000000000000000000000000000000000000000000000001498.9999999999 +1499,900000000000000000000000000000000000000000000000000000000000001499.9999999999 +1500,900000000000000000000000000000000000000000000000000000000000001500.9999999999 +1501,900000000000000000000000000000000000000000000000000000000000001501.9999999999 +1502,900000000000000000000000000000000000000000000000000000000000001502.9999999999 +1503,900000000000000000000000000000000000000000000000000000000000001503.9999999999 +1504,900000000000000000000000000000000000000000000000000000000000001504.9999999999 +1505,900000000000000000000000000000000000000000000000000000000000001505.9999999999 +1506,900000000000000000000000000000000000000000000000000000000000001506.9999999999 +1507,900000000000000000000000000000000000000000000000000000000000001507.9999999999 +1508,900000000000000000000000000000000000000000000000000000000000001508.9999999999 +1509,900000000000000000000000000000000000000000000000000000000000001509.9999999999 +1510,900000000000000000000000000000000000000000000000000000000000001510.9999999999 +1511,900000000000000000000000000000000000000000000000000000000000001511.9999999999 +1512,900000000000000000000000000000000000000000000000000000000000001512.9999999999 +1513,900000000000000000000000000000000000000000000000000000000000001513.9999999999 +1514,900000000000000000000000000000000000000000000000000000000000001514.9999999999 +1515,900000000000000000000000000000000000000000000000000000000000001515.9999999999 +1516,900000000000000000000000000000000000000000000000000000000000001516.9999999999 +1517,900000000000000000000000000000000000000000000000000000000000001517.9999999999 +1518,900000000000000000000000000000000000000000000000000000000000001518.9999999999 +1519,900000000000000000000000000000000000000000000000000000000000001519.9999999999 +1520,900000000000000000000000000000000000000000000000000000000000001520.9999999999 +1521,900000000000000000000000000000000000000000000000000000000000001521.9999999999 +1522,900000000000000000000000000000000000000000000000000000000000001522.9999999999 +1523,900000000000000000000000000000000000000000000000000000000000001523.9999999999 +1524,900000000000000000000000000000000000000000000000000000000000001524.9999999999 +1525,900000000000000000000000000000000000000000000000000000000000001525.9999999999 +1526,900000000000000000000000000000000000000000000000000000000000001526.9999999999 +1527,900000000000000000000000000000000000000000000000000000000000001527.9999999999 +1528,900000000000000000000000000000000000000000000000000000000000001528.9999999999 +1529,900000000000000000000000000000000000000000000000000000000000001529.9999999999 +1530,900000000000000000000000000000000000000000000000000000000000001530.9999999999 +1531,900000000000000000000000000000000000000000000000000000000000001531.9999999999 +1532,900000000000000000000000000000000000000000000000000000000000001532.9999999999 +1533,900000000000000000000000000000000000000000000000000000000000001533.9999999999 +1534,900000000000000000000000000000000000000000000000000000000000001534.9999999999 +1535,900000000000000000000000000000000000000000000000000000000000001535.9999999999 +1536,900000000000000000000000000000000000000000000000000000000000001536.9999999999 +1537,900000000000000000000000000000000000000000000000000000000000001537.9999999999 +1538,900000000000000000000000000000000000000000000000000000000000001538.9999999999 +1539,900000000000000000000000000000000000000000000000000000000000001539.9999999999 +1540,900000000000000000000000000000000000000000000000000000000000001540.9999999999 +1541,900000000000000000000000000000000000000000000000000000000000001541.9999999999 +1542,900000000000000000000000000000000000000000000000000000000000001542.9999999999 +1543,900000000000000000000000000000000000000000000000000000000000001543.9999999999 +1544,900000000000000000000000000000000000000000000000000000000000001544.9999999999 +1545,900000000000000000000000000000000000000000000000000000000000001545.9999999999 +1546,900000000000000000000000000000000000000000000000000000000000001546.9999999999 +1547,900000000000000000000000000000000000000000000000000000000000001547.9999999999 +1548,900000000000000000000000000000000000000000000000000000000000001548.9999999999 +1549,900000000000000000000000000000000000000000000000000000000000001549.9999999999 +1550,900000000000000000000000000000000000000000000000000000000000001550.9999999999 +1551,900000000000000000000000000000000000000000000000000000000000001551.9999999999 +1552,900000000000000000000000000000000000000000000000000000000000001552.9999999999 +1553,900000000000000000000000000000000000000000000000000000000000001553.9999999999 +1554,900000000000000000000000000000000000000000000000000000000000001554.9999999999 +1555,900000000000000000000000000000000000000000000000000000000000001555.9999999999 +1556,900000000000000000000000000000000000000000000000000000000000001556.9999999999 +1557,900000000000000000000000000000000000000000000000000000000000001557.9999999999 +1558,900000000000000000000000000000000000000000000000000000000000001558.9999999999 +1559,900000000000000000000000000000000000000000000000000000000000001559.9999999999 +1560,900000000000000000000000000000000000000000000000000000000000001560.9999999999 +1561,900000000000000000000000000000000000000000000000000000000000001561.9999999999 +1562,900000000000000000000000000000000000000000000000000000000000001562.9999999999 +1563,900000000000000000000000000000000000000000000000000000000000001563.9999999999 +1564,900000000000000000000000000000000000000000000000000000000000001564.9999999999 +1565,900000000000000000000000000000000000000000000000000000000000001565.9999999999 +1566,900000000000000000000000000000000000000000000000000000000000001566.9999999999 +1567,900000000000000000000000000000000000000000000000000000000000001567.9999999999 +1568,900000000000000000000000000000000000000000000000000000000000001568.9999999999 +1569,900000000000000000000000000000000000000000000000000000000000001569.9999999999 +1570,900000000000000000000000000000000000000000000000000000000000001570.9999999999 +1571,900000000000000000000000000000000000000000000000000000000000001571.9999999999 +1572,900000000000000000000000000000000000000000000000000000000000001572.9999999999 +1573,900000000000000000000000000000000000000000000000000000000000001573.9999999999 +1574,900000000000000000000000000000000000000000000000000000000000001574.9999999999 +1575,900000000000000000000000000000000000000000000000000000000000001575.9999999999 +1576,900000000000000000000000000000000000000000000000000000000000001576.9999999999 +1577,900000000000000000000000000000000000000000000000000000000000001577.9999999999 +1578,900000000000000000000000000000000000000000000000000000000000001578.9999999999 +1579,900000000000000000000000000000000000000000000000000000000000001579.9999999999 +1580,900000000000000000000000000000000000000000000000000000000000001580.9999999999 +1581,900000000000000000000000000000000000000000000000000000000000001581.9999999999 +1582,900000000000000000000000000000000000000000000000000000000000001582.9999999999 +1583,900000000000000000000000000000000000000000000000000000000000001583.9999999999 +1584,900000000000000000000000000000000000000000000000000000000000001584.9999999999 +1585,900000000000000000000000000000000000000000000000000000000000001585.9999999999 +1586,900000000000000000000000000000000000000000000000000000000000001586.9999999999 +1587,900000000000000000000000000000000000000000000000000000000000001587.9999999999 +1588,900000000000000000000000000000000000000000000000000000000000001588.9999999999 +1589,900000000000000000000000000000000000000000000000000000000000001589.9999999999 +1590,900000000000000000000000000000000000000000000000000000000000001590.9999999999 +1591,900000000000000000000000000000000000000000000000000000000000001591.9999999999 +1592,900000000000000000000000000000000000000000000000000000000000001592.9999999999 +1593,900000000000000000000000000000000000000000000000000000000000001593.9999999999 +1594,900000000000000000000000000000000000000000000000000000000000001594.9999999999 +1595,900000000000000000000000000000000000000000000000000000000000001595.9999999999 +1596,900000000000000000000000000000000000000000000000000000000000001596.9999999999 +1597,900000000000000000000000000000000000000000000000000000000000001597.9999999999 +1598,900000000000000000000000000000000000000000000000000000000000001598.9999999999 +1599,900000000000000000000000000000000000000000000000000000000000001599.9999999999 +1600,900000000000000000000000000000000000000000000000000000000000001600.9999999999 +1601,900000000000000000000000000000000000000000000000000000000000001601.9999999999 +1602,900000000000000000000000000000000000000000000000000000000000001602.9999999999 +1603,900000000000000000000000000000000000000000000000000000000000001603.9999999999 +1604,900000000000000000000000000000000000000000000000000000000000001604.9999999999 +1605,900000000000000000000000000000000000000000000000000000000000001605.9999999999 +1606,900000000000000000000000000000000000000000000000000000000000001606.9999999999 +1607,900000000000000000000000000000000000000000000000000000000000001607.9999999999 +1608,900000000000000000000000000000000000000000000000000000000000001608.9999999999 +1609,900000000000000000000000000000000000000000000000000000000000001609.9999999999 +1610,900000000000000000000000000000000000000000000000000000000000001610.9999999999 +1611,900000000000000000000000000000000000000000000000000000000000001611.9999999999 +1612,900000000000000000000000000000000000000000000000000000000000001612.9999999999 +1613,900000000000000000000000000000000000000000000000000000000000001613.9999999999 +1614,900000000000000000000000000000000000000000000000000000000000001614.9999999999 +1615,900000000000000000000000000000000000000000000000000000000000001615.9999999999 +1616,900000000000000000000000000000000000000000000000000000000000001616.9999999999 +1617,900000000000000000000000000000000000000000000000000000000000001617.9999999999 +1618,900000000000000000000000000000000000000000000000000000000000001618.9999999999 +1619,900000000000000000000000000000000000000000000000000000000000001619.9999999999 +1620,900000000000000000000000000000000000000000000000000000000000001620.9999999999 +1621,900000000000000000000000000000000000000000000000000000000000001621.9999999999 +1622,900000000000000000000000000000000000000000000000000000000000001622.9999999999 +1623,900000000000000000000000000000000000000000000000000000000000001623.9999999999 +1624,900000000000000000000000000000000000000000000000000000000000001624.9999999999 +1625,900000000000000000000000000000000000000000000000000000000000001625.9999999999 +1626,900000000000000000000000000000000000000000000000000000000000001626.9999999999 +1627,900000000000000000000000000000000000000000000000000000000000001627.9999999999 +1628,900000000000000000000000000000000000000000000000000000000000001628.9999999999 +1629,900000000000000000000000000000000000000000000000000000000000001629.9999999999 +1630,900000000000000000000000000000000000000000000000000000000000001630.9999999999 +1631,900000000000000000000000000000000000000000000000000000000000001631.9999999999 +1632,900000000000000000000000000000000000000000000000000000000000001632.9999999999 +1633,900000000000000000000000000000000000000000000000000000000000001633.9999999999 +1634,900000000000000000000000000000000000000000000000000000000000001634.9999999999 +1635,900000000000000000000000000000000000000000000000000000000000001635.9999999999 +1636,900000000000000000000000000000000000000000000000000000000000001636.9999999999 +1637,900000000000000000000000000000000000000000000000000000000000001637.9999999999 +1638,900000000000000000000000000000000000000000000000000000000000001638.9999999999 +1639,900000000000000000000000000000000000000000000000000000000000001639.9999999999 +1640,900000000000000000000000000000000000000000000000000000000000001640.9999999999 +1641,900000000000000000000000000000000000000000000000000000000000001641.9999999999 +1642,900000000000000000000000000000000000000000000000000000000000001642.9999999999 +1643,900000000000000000000000000000000000000000000000000000000000001643.9999999999 +1644,900000000000000000000000000000000000000000000000000000000000001644.9999999999 +1645,900000000000000000000000000000000000000000000000000000000000001645.9999999999 +1646,900000000000000000000000000000000000000000000000000000000000001646.9999999999 +1647,900000000000000000000000000000000000000000000000000000000000001647.9999999999 +1648,900000000000000000000000000000000000000000000000000000000000001648.9999999999 +1649,900000000000000000000000000000000000000000000000000000000000001649.9999999999 +1650,900000000000000000000000000000000000000000000000000000000000001650.9999999999 +1651,900000000000000000000000000000000000000000000000000000000000001651.9999999999 +1652,900000000000000000000000000000000000000000000000000000000000001652.9999999999 +1653,900000000000000000000000000000000000000000000000000000000000001653.9999999999 +1654,900000000000000000000000000000000000000000000000000000000000001654.9999999999 +1655,900000000000000000000000000000000000000000000000000000000000001655.9999999999 +1656,900000000000000000000000000000000000000000000000000000000000001656.9999999999 +1657,900000000000000000000000000000000000000000000000000000000000001657.9999999999 +1658,900000000000000000000000000000000000000000000000000000000000001658.9999999999 +1659,900000000000000000000000000000000000000000000000000000000000001659.9999999999 +1660,900000000000000000000000000000000000000000000000000000000000001660.9999999999 +1661,900000000000000000000000000000000000000000000000000000000000001661.9999999999 +1662,900000000000000000000000000000000000000000000000000000000000001662.9999999999 +1663,900000000000000000000000000000000000000000000000000000000000001663.9999999999 +1664,900000000000000000000000000000000000000000000000000000000000001664.9999999999 +1665,900000000000000000000000000000000000000000000000000000000000001665.9999999999 +1666,900000000000000000000000000000000000000000000000000000000000001666.9999999999 +1667,900000000000000000000000000000000000000000000000000000000000001667.9999999999 +1668,900000000000000000000000000000000000000000000000000000000000001668.9999999999 +1669,900000000000000000000000000000000000000000000000000000000000001669.9999999999 +1670,900000000000000000000000000000000000000000000000000000000000001670.9999999999 +1671,900000000000000000000000000000000000000000000000000000000000001671.9999999999 +1672,900000000000000000000000000000000000000000000000000000000000001672.9999999999 +1673,900000000000000000000000000000000000000000000000000000000000001673.9999999999 +1674,900000000000000000000000000000000000000000000000000000000000001674.9999999999 +1675,900000000000000000000000000000000000000000000000000000000000001675.9999999999 +1676,900000000000000000000000000000000000000000000000000000000000001676.9999999999 +1677,900000000000000000000000000000000000000000000000000000000000001677.9999999999 +1678,900000000000000000000000000000000000000000000000000000000000001678.9999999999 +1679,900000000000000000000000000000000000000000000000000000000000001679.9999999999 +1680,900000000000000000000000000000000000000000000000000000000000001680.9999999999 +1681,900000000000000000000000000000000000000000000000000000000000001681.9999999999 +1682,900000000000000000000000000000000000000000000000000000000000001682.9999999999 +1683,900000000000000000000000000000000000000000000000000000000000001683.9999999999 +1684,900000000000000000000000000000000000000000000000000000000000001684.9999999999 +1685,900000000000000000000000000000000000000000000000000000000000001685.9999999999 +1686,900000000000000000000000000000000000000000000000000000000000001686.9999999999 +1687,900000000000000000000000000000000000000000000000000000000000001687.9999999999 +1688,900000000000000000000000000000000000000000000000000000000000001688.9999999999 +1689,900000000000000000000000000000000000000000000000000000000000001689.9999999999 +1690,900000000000000000000000000000000000000000000000000000000000001690.9999999999 +1691,900000000000000000000000000000000000000000000000000000000000001691.9999999999 +1692,900000000000000000000000000000000000000000000000000000000000001692.9999999999 +1693,900000000000000000000000000000000000000000000000000000000000001693.9999999999 +1694,900000000000000000000000000000000000000000000000000000000000001694.9999999999 +1695,900000000000000000000000000000000000000000000000000000000000001695.9999999999 +1696,900000000000000000000000000000000000000000000000000000000000001696.9999999999 +1697,900000000000000000000000000000000000000000000000000000000000001697.9999999999 +1698,900000000000000000000000000000000000000000000000000000000000001698.9999999999 +1699,900000000000000000000000000000000000000000000000000000000000001699.9999999999 +1700,900000000000000000000000000000000000000000000000000000000000001700.9999999999 +1701,900000000000000000000000000000000000000000000000000000000000001701.9999999999 +1702,900000000000000000000000000000000000000000000000000000000000001702.9999999999 +1703,900000000000000000000000000000000000000000000000000000000000001703.9999999999 +1704,900000000000000000000000000000000000000000000000000000000000001704.9999999999 +1705,900000000000000000000000000000000000000000000000000000000000001705.9999999999 +1706,900000000000000000000000000000000000000000000000000000000000001706.9999999999 +1707,900000000000000000000000000000000000000000000000000000000000001707.9999999999 +1708,900000000000000000000000000000000000000000000000000000000000001708.9999999999 +1709,900000000000000000000000000000000000000000000000000000000000001709.9999999999 +1710,900000000000000000000000000000000000000000000000000000000000001710.9999999999 +1711,900000000000000000000000000000000000000000000000000000000000001711.9999999999 +1712,900000000000000000000000000000000000000000000000000000000000001712.9999999999 +1713,900000000000000000000000000000000000000000000000000000000000001713.9999999999 +1714,900000000000000000000000000000000000000000000000000000000000001714.9999999999 +1715,900000000000000000000000000000000000000000000000000000000000001715.9999999999 +1716,900000000000000000000000000000000000000000000000000000000000001716.9999999999 +1717,900000000000000000000000000000000000000000000000000000000000001717.9999999999 +1718,900000000000000000000000000000000000000000000000000000000000001718.9999999999 +1719,900000000000000000000000000000000000000000000000000000000000001719.9999999999 +1720,900000000000000000000000000000000000000000000000000000000000001720.9999999999 +1721,900000000000000000000000000000000000000000000000000000000000001721.9999999999 +1722,900000000000000000000000000000000000000000000000000000000000001722.9999999999 +1723,900000000000000000000000000000000000000000000000000000000000001723.9999999999 +1724,900000000000000000000000000000000000000000000000000000000000001724.9999999999 +1725,900000000000000000000000000000000000000000000000000000000000001725.9999999999 +1726,900000000000000000000000000000000000000000000000000000000000001726.9999999999 +1727,900000000000000000000000000000000000000000000000000000000000001727.9999999999 +1728,900000000000000000000000000000000000000000000000000000000000001728.9999999999 +1729,900000000000000000000000000000000000000000000000000000000000001729.9999999999 +1730,900000000000000000000000000000000000000000000000000000000000001730.9999999999 +1731,900000000000000000000000000000000000000000000000000000000000001731.9999999999 +1732,900000000000000000000000000000000000000000000000000000000000001732.9999999999 +1733,900000000000000000000000000000000000000000000000000000000000001733.9999999999 +1734,900000000000000000000000000000000000000000000000000000000000001734.9999999999 +1735,900000000000000000000000000000000000000000000000000000000000001735.9999999999 +1736,900000000000000000000000000000000000000000000000000000000000001736.9999999999 +1737,900000000000000000000000000000000000000000000000000000000000001737.9999999999 +1738,900000000000000000000000000000000000000000000000000000000000001738.9999999999 +1739,900000000000000000000000000000000000000000000000000000000000001739.9999999999 +1740,900000000000000000000000000000000000000000000000000000000000001740.9999999999 +1741,900000000000000000000000000000000000000000000000000000000000001741.9999999999 +1742,900000000000000000000000000000000000000000000000000000000000001742.9999999999 +1743,900000000000000000000000000000000000000000000000000000000000001743.9999999999 +1744,900000000000000000000000000000000000000000000000000000000000001744.9999999999 +1745,900000000000000000000000000000000000000000000000000000000000001745.9999999999 +1746,900000000000000000000000000000000000000000000000000000000000001746.9999999999 +1747,900000000000000000000000000000000000000000000000000000000000001747.9999999999 +1748,900000000000000000000000000000000000000000000000000000000000001748.9999999999 +1749,900000000000000000000000000000000000000000000000000000000000001749.9999999999 +1750,900000000000000000000000000000000000000000000000000000000000001750.9999999999 +1751,900000000000000000000000000000000000000000000000000000000000001751.9999999999 +1752,900000000000000000000000000000000000000000000000000000000000001752.9999999999 +1753,900000000000000000000000000000000000000000000000000000000000001753.9999999999 +1754,900000000000000000000000000000000000000000000000000000000000001754.9999999999 +1755,900000000000000000000000000000000000000000000000000000000000001755.9999999999 +1756,900000000000000000000000000000000000000000000000000000000000001756.9999999999 +1757,900000000000000000000000000000000000000000000000000000000000001757.9999999999 +1758,900000000000000000000000000000000000000000000000000000000000001758.9999999999 +1759,900000000000000000000000000000000000000000000000000000000000001759.9999999999 +1760,900000000000000000000000000000000000000000000000000000000000001760.9999999999 +1761,900000000000000000000000000000000000000000000000000000000000001761.9999999999 +1762,900000000000000000000000000000000000000000000000000000000000001762.9999999999 +1763,900000000000000000000000000000000000000000000000000000000000001763.9999999999 +1764,900000000000000000000000000000000000000000000000000000000000001764.9999999999 +1765,900000000000000000000000000000000000000000000000000000000000001765.9999999999 +1766,900000000000000000000000000000000000000000000000000000000000001766.9999999999 +1767,900000000000000000000000000000000000000000000000000000000000001767.9999999999 +1768,900000000000000000000000000000000000000000000000000000000000001768.9999999999 +1769,900000000000000000000000000000000000000000000000000000000000001769.9999999999 +1770,900000000000000000000000000000000000000000000000000000000000001770.9999999999 +1771,900000000000000000000000000000000000000000000000000000000000001771.9999999999 +1772,900000000000000000000000000000000000000000000000000000000000001772.9999999999 +1773,900000000000000000000000000000000000000000000000000000000000001773.9999999999 +1774,900000000000000000000000000000000000000000000000000000000000001774.9999999999 +1775,900000000000000000000000000000000000000000000000000000000000001775.9999999999 +1776,900000000000000000000000000000000000000000000000000000000000001776.9999999999 +1777,900000000000000000000000000000000000000000000000000000000000001777.9999999999 +1778,900000000000000000000000000000000000000000000000000000000000001778.9999999999 +1779,900000000000000000000000000000000000000000000000000000000000001779.9999999999 +1780,900000000000000000000000000000000000000000000000000000000000001780.9999999999 +1781,900000000000000000000000000000000000000000000000000000000000001781.9999999999 +1782,900000000000000000000000000000000000000000000000000000000000001782.9999999999 +1783,900000000000000000000000000000000000000000000000000000000000001783.9999999999 +1784,900000000000000000000000000000000000000000000000000000000000001784.9999999999 +1785,900000000000000000000000000000000000000000000000000000000000001785.9999999999 +1786,900000000000000000000000000000000000000000000000000000000000001786.9999999999 +1787,900000000000000000000000000000000000000000000000000000000000001787.9999999999 +1788,900000000000000000000000000000000000000000000000000000000000001788.9999999999 +1789,900000000000000000000000000000000000000000000000000000000000001789.9999999999 +1790,900000000000000000000000000000000000000000000000000000000000001790.9999999999 +1791,900000000000000000000000000000000000000000000000000000000000001791.9999999999 +1792,900000000000000000000000000000000000000000000000000000000000001792.9999999999 +1793,900000000000000000000000000000000000000000000000000000000000001793.9999999999 +1794,900000000000000000000000000000000000000000000000000000000000001794.9999999999 +1795,900000000000000000000000000000000000000000000000000000000000001795.9999999999 +1796,900000000000000000000000000000000000000000000000000000000000001796.9999999999 +1797,900000000000000000000000000000000000000000000000000000000000001797.9999999999 +1798,900000000000000000000000000000000000000000000000000000000000001798.9999999999 +1799,900000000000000000000000000000000000000000000000000000000000001799.9999999999 +1800,900000000000000000000000000000000000000000000000000000000000001800.9999999999 +1801,900000000000000000000000000000000000000000000000000000000000001801.9999999999 +1802,900000000000000000000000000000000000000000000000000000000000001802.9999999999 +1803,900000000000000000000000000000000000000000000000000000000000001803.9999999999 +1804,900000000000000000000000000000000000000000000000000000000000001804.9999999999 +1805,900000000000000000000000000000000000000000000000000000000000001805.9999999999 +1806,900000000000000000000000000000000000000000000000000000000000001806.9999999999 +1807,900000000000000000000000000000000000000000000000000000000000001807.9999999999 +1808,900000000000000000000000000000000000000000000000000000000000001808.9999999999 +1809,900000000000000000000000000000000000000000000000000000000000001809.9999999999 +1810,900000000000000000000000000000000000000000000000000000000000001810.9999999999 +1811,900000000000000000000000000000000000000000000000000000000000001811.9999999999 +1812,900000000000000000000000000000000000000000000000000000000000001812.9999999999 +1813,900000000000000000000000000000000000000000000000000000000000001813.9999999999 +1814,900000000000000000000000000000000000000000000000000000000000001814.9999999999 +1815,900000000000000000000000000000000000000000000000000000000000001815.9999999999 +1816,900000000000000000000000000000000000000000000000000000000000001816.9999999999 +1817,900000000000000000000000000000000000000000000000000000000000001817.9999999999 +1818,900000000000000000000000000000000000000000000000000000000000001818.9999999999 +1819,900000000000000000000000000000000000000000000000000000000000001819.9999999999 +1820,900000000000000000000000000000000000000000000000000000000000001820.9999999999 +1821,900000000000000000000000000000000000000000000000000000000000001821.9999999999 +1822,900000000000000000000000000000000000000000000000000000000000001822.9999999999 +1823,900000000000000000000000000000000000000000000000000000000000001823.9999999999 +1824,900000000000000000000000000000000000000000000000000000000000001824.9999999999 +1825,900000000000000000000000000000000000000000000000000000000000001825.9999999999 +1826,900000000000000000000000000000000000000000000000000000000000001826.9999999999 +1827,900000000000000000000000000000000000000000000000000000000000001827.9999999999 +1828,900000000000000000000000000000000000000000000000000000000000001828.9999999999 +1829,900000000000000000000000000000000000000000000000000000000000001829.9999999999 +1830,900000000000000000000000000000000000000000000000000000000000001830.9999999999 +1831,900000000000000000000000000000000000000000000000000000000000001831.9999999999 +1832,900000000000000000000000000000000000000000000000000000000000001832.9999999999 +1833,900000000000000000000000000000000000000000000000000000000000001833.9999999999 +1834,900000000000000000000000000000000000000000000000000000000000001834.9999999999 +1835,900000000000000000000000000000000000000000000000000000000000001835.9999999999 +1836,900000000000000000000000000000000000000000000000000000000000001836.9999999999 +1837,900000000000000000000000000000000000000000000000000000000000001837.9999999999 +1838,900000000000000000000000000000000000000000000000000000000000001838.9999999999 +1839,900000000000000000000000000000000000000000000000000000000000001839.9999999999 +1840,900000000000000000000000000000000000000000000000000000000000001840.9999999999 +1841,900000000000000000000000000000000000000000000000000000000000001841.9999999999 +1842,900000000000000000000000000000000000000000000000000000000000001842.9999999999 +1843,900000000000000000000000000000000000000000000000000000000000001843.9999999999 +1844,900000000000000000000000000000000000000000000000000000000000001844.9999999999 +1845,900000000000000000000000000000000000000000000000000000000000001845.9999999999 +1846,900000000000000000000000000000000000000000000000000000000000001846.9999999999 +1847,900000000000000000000000000000000000000000000000000000000000001847.9999999999 +1848,900000000000000000000000000000000000000000000000000000000000001848.9999999999 +1849,900000000000000000000000000000000000000000000000000000000000001849.9999999999 +1850,900000000000000000000000000000000000000000000000000000000000001850.9999999999 +1851,900000000000000000000000000000000000000000000000000000000000001851.9999999999 +1852,900000000000000000000000000000000000000000000000000000000000001852.9999999999 +1853,900000000000000000000000000000000000000000000000000000000000001853.9999999999 +1854,900000000000000000000000000000000000000000000000000000000000001854.9999999999 +1855,900000000000000000000000000000000000000000000000000000000000001855.9999999999 +1856,900000000000000000000000000000000000000000000000000000000000001856.9999999999 +1857,900000000000000000000000000000000000000000000000000000000000001857.9999999999 +1858,900000000000000000000000000000000000000000000000000000000000001858.9999999999 +1859,900000000000000000000000000000000000000000000000000000000000001859.9999999999 +1860,900000000000000000000000000000000000000000000000000000000000001860.9999999999 +1861,900000000000000000000000000000000000000000000000000000000000001861.9999999999 +1862,900000000000000000000000000000000000000000000000000000000000001862.9999999999 +1863,900000000000000000000000000000000000000000000000000000000000001863.9999999999 +1864,900000000000000000000000000000000000000000000000000000000000001864.9999999999 +1865,900000000000000000000000000000000000000000000000000000000000001865.9999999999 +1866,900000000000000000000000000000000000000000000000000000000000001866.9999999999 +1867,900000000000000000000000000000000000000000000000000000000000001867.9999999999 +1868,900000000000000000000000000000000000000000000000000000000000001868.9999999999 +1869,900000000000000000000000000000000000000000000000000000000000001869.9999999999 +1870,900000000000000000000000000000000000000000000000000000000000001870.9999999999 +1871,900000000000000000000000000000000000000000000000000000000000001871.9999999999 +1872,900000000000000000000000000000000000000000000000000000000000001872.9999999999 +1873,900000000000000000000000000000000000000000000000000000000000001873.9999999999 +1874,900000000000000000000000000000000000000000000000000000000000001874.9999999999 +1875,900000000000000000000000000000000000000000000000000000000000001875.9999999999 +1876,900000000000000000000000000000000000000000000000000000000000001876.9999999999 +1877,900000000000000000000000000000000000000000000000000000000000001877.9999999999 +1878,900000000000000000000000000000000000000000000000000000000000001878.9999999999 +1879,900000000000000000000000000000000000000000000000000000000000001879.9999999999 +1880,900000000000000000000000000000000000000000000000000000000000001880.9999999999 +1881,900000000000000000000000000000000000000000000000000000000000001881.9999999999 +1882,900000000000000000000000000000000000000000000000000000000000001882.9999999999 +1883,900000000000000000000000000000000000000000000000000000000000001883.9999999999 +1884,900000000000000000000000000000000000000000000000000000000000001884.9999999999 +1885,900000000000000000000000000000000000000000000000000000000000001885.9999999999 +1886,900000000000000000000000000000000000000000000000000000000000001886.9999999999 +1887,900000000000000000000000000000000000000000000000000000000000001887.9999999999 +1888,900000000000000000000000000000000000000000000000000000000000001888.9999999999 +1889,900000000000000000000000000000000000000000000000000000000000001889.9999999999 +1890,900000000000000000000000000000000000000000000000000000000000001890.9999999999 +1891,900000000000000000000000000000000000000000000000000000000000001891.9999999999 +1892,900000000000000000000000000000000000000000000000000000000000001892.9999999999 +1893,900000000000000000000000000000000000000000000000000000000000001893.9999999999 +1894,900000000000000000000000000000000000000000000000000000000000001894.9999999999 +1895,900000000000000000000000000000000000000000000000000000000000001895.9999999999 +1896,900000000000000000000000000000000000000000000000000000000000001896.9999999999 +1897,900000000000000000000000000000000000000000000000000000000000001897.9999999999 +1898,900000000000000000000000000000000000000000000000000000000000001898.9999999999 +1899,900000000000000000000000000000000000000000000000000000000000001899.9999999999 +1900,900000000000000000000000000000000000000000000000000000000000001900.9999999999 +1901,900000000000000000000000000000000000000000000000000000000000001901.9999999999 +1902,900000000000000000000000000000000000000000000000000000000000001902.9999999999 +1903,900000000000000000000000000000000000000000000000000000000000001903.9999999999 +1904,900000000000000000000000000000000000000000000000000000000000001904.9999999999 +1905,900000000000000000000000000000000000000000000000000000000000001905.9999999999 +1906,900000000000000000000000000000000000000000000000000000000000001906.9999999999 +1907,900000000000000000000000000000000000000000000000000000000000001907.9999999999 +1908,900000000000000000000000000000000000000000000000000000000000001908.9999999999 +1909,900000000000000000000000000000000000000000000000000000000000001909.9999999999 +1910,900000000000000000000000000000000000000000000000000000000000001910.9999999999 +1911,900000000000000000000000000000000000000000000000000000000000001911.9999999999 +1912,900000000000000000000000000000000000000000000000000000000000001912.9999999999 +1913,900000000000000000000000000000000000000000000000000000000000001913.9999999999 +1914,900000000000000000000000000000000000000000000000000000000000001914.9999999999 +1915,900000000000000000000000000000000000000000000000000000000000001915.9999999999 +1916,900000000000000000000000000000000000000000000000000000000000001916.9999999999 +1917,900000000000000000000000000000000000000000000000000000000000001917.9999999999 +1918,900000000000000000000000000000000000000000000000000000000000001918.9999999999 +1919,900000000000000000000000000000000000000000000000000000000000001919.9999999999 +1920,900000000000000000000000000000000000000000000000000000000000001920.9999999999 +1921,900000000000000000000000000000000000000000000000000000000000001921.9999999999 +1922,900000000000000000000000000000000000000000000000000000000000001922.9999999999 +1923,900000000000000000000000000000000000000000000000000000000000001923.9999999999 +1924,900000000000000000000000000000000000000000000000000000000000001924.9999999999 +1925,900000000000000000000000000000000000000000000000000000000000001925.9999999999 +1926,900000000000000000000000000000000000000000000000000000000000001926.9999999999 +1927,900000000000000000000000000000000000000000000000000000000000001927.9999999999 +1928,900000000000000000000000000000000000000000000000000000000000001928.9999999999 +1929,900000000000000000000000000000000000000000000000000000000000001929.9999999999 +1930,900000000000000000000000000000000000000000000000000000000000001930.9999999999 +1931,900000000000000000000000000000000000000000000000000000000000001931.9999999999 +1932,900000000000000000000000000000000000000000000000000000000000001932.9999999999 +1933,900000000000000000000000000000000000000000000000000000000000001933.9999999999 +1934,900000000000000000000000000000000000000000000000000000000000001934.9999999999 +1935,900000000000000000000000000000000000000000000000000000000000001935.9999999999 +1936,900000000000000000000000000000000000000000000000000000000000001936.9999999999 +1937,900000000000000000000000000000000000000000000000000000000000001937.9999999999 +1938,900000000000000000000000000000000000000000000000000000000000001938.9999999999 +1939,900000000000000000000000000000000000000000000000000000000000001939.9999999999 +1940,900000000000000000000000000000000000000000000000000000000000001940.9999999999 +1941,900000000000000000000000000000000000000000000000000000000000001941.9999999999 +1942,900000000000000000000000000000000000000000000000000000000000001942.9999999999 +1943,900000000000000000000000000000000000000000000000000000000000001943.9999999999 +1944,900000000000000000000000000000000000000000000000000000000000001944.9999999999 +1945,900000000000000000000000000000000000000000000000000000000000001945.9999999999 +1946,900000000000000000000000000000000000000000000000000000000000001946.9999999999 +1947,900000000000000000000000000000000000000000000000000000000000001947.9999999999 +1948,900000000000000000000000000000000000000000000000000000000000001948.9999999999 +1949,900000000000000000000000000000000000000000000000000000000000001949.9999999999 +1950,900000000000000000000000000000000000000000000000000000000000001950.9999999999 +1951,900000000000000000000000000000000000000000000000000000000000001951.9999999999 +1952,900000000000000000000000000000000000000000000000000000000000001952.9999999999 +1953,900000000000000000000000000000000000000000000000000000000000001953.9999999999 +1954,900000000000000000000000000000000000000000000000000000000000001954.9999999999 +1955,900000000000000000000000000000000000000000000000000000000000001955.9999999999 +1956,900000000000000000000000000000000000000000000000000000000000001956.9999999999 +1957,900000000000000000000000000000000000000000000000000000000000001957.9999999999 +1958,900000000000000000000000000000000000000000000000000000000000001958.9999999999 +1959,900000000000000000000000000000000000000000000000000000000000001959.9999999999 +1960,900000000000000000000000000000000000000000000000000000000000001960.9999999999 +1961,900000000000000000000000000000000000000000000000000000000000001961.9999999999 +1962,900000000000000000000000000000000000000000000000000000000000001962.9999999999 +1963,900000000000000000000000000000000000000000000000000000000000001963.9999999999 +1964,900000000000000000000000000000000000000000000000000000000000001964.9999999999 +1965,900000000000000000000000000000000000000000000000000000000000001965.9999999999 +1966,900000000000000000000000000000000000000000000000000000000000001966.9999999999 +1967,900000000000000000000000000000000000000000000000000000000000001967.9999999999 +1968,900000000000000000000000000000000000000000000000000000000000001968.9999999999 +1969,900000000000000000000000000000000000000000000000000000000000001969.9999999999 +1970,900000000000000000000000000000000000000000000000000000000000001970.9999999999 +1971,900000000000000000000000000000000000000000000000000000000000001971.9999999999 +1972,900000000000000000000000000000000000000000000000000000000000001972.9999999999 +1973,900000000000000000000000000000000000000000000000000000000000001973.9999999999 +1974,900000000000000000000000000000000000000000000000000000000000001974.9999999999 +1975,900000000000000000000000000000000000000000000000000000000000001975.9999999999 +1976,900000000000000000000000000000000000000000000000000000000000001976.9999999999 +1977,900000000000000000000000000000000000000000000000000000000000001977.9999999999 +1978,900000000000000000000000000000000000000000000000000000000000001978.9999999999 +1979,900000000000000000000000000000000000000000000000000000000000001979.9999999999 +1980,900000000000000000000000000000000000000000000000000000000000001980.9999999999 +1981,900000000000000000000000000000000000000000000000000000000000001981.9999999999 +1982,900000000000000000000000000000000000000000000000000000000000001982.9999999999 +1983,900000000000000000000000000000000000000000000000000000000000001983.9999999999 +1984,900000000000000000000000000000000000000000000000000000000000001984.9999999999 +1985,900000000000000000000000000000000000000000000000000000000000001985.9999999999 +1986,900000000000000000000000000000000000000000000000000000000000001986.9999999999 +1987,900000000000000000000000000000000000000000000000000000000000001987.9999999999 +1988,900000000000000000000000000000000000000000000000000000000000001988.9999999999 +1989,900000000000000000000000000000000000000000000000000000000000001989.9999999999 +1990,900000000000000000000000000000000000000000000000000000000000001990.9999999999 +1991,900000000000000000000000000000000000000000000000000000000000001991.9999999999 +1992,900000000000000000000000000000000000000000000000000000000000001992.9999999999 +1993,900000000000000000000000000000000000000000000000000000000000001993.9999999999 +1994,900000000000000000000000000000000000000000000000000000000000001994.9999999999 +1995,900000000000000000000000000000000000000000000000000000000000001995.9999999999 +1996,900000000000000000000000000000000000000000000000000000000000001996.9999999999 +1997,900000000000000000000000000000000000000000000000000000000000001997.9999999999 +1998,900000000000000000000000000000000000000000000000000000000000001998.9999999999 +1999,900000000000000000000000000000000000000000000000000000000000001999.9999999999 +2000,900000000000000000000000000000000000000000000000000000000000002000.9999999999 +2001,900000000000000000000000000000000000000000000000000000000000002001.9999999999 +2002,900000000000000000000000000000000000000000000000000000000000002002.9999999999 +2003,900000000000000000000000000000000000000000000000000000000000002003.9999999999 +2004,900000000000000000000000000000000000000000000000000000000000002004.9999999999 +2005,900000000000000000000000000000000000000000000000000000000000002005.9999999999 +2006,900000000000000000000000000000000000000000000000000000000000002006.9999999999 +2007,900000000000000000000000000000000000000000000000000000000000002007.9999999999 +2008,900000000000000000000000000000000000000000000000000000000000002008.9999999999 +2009,900000000000000000000000000000000000000000000000000000000000002009.9999999999 +2010,900000000000000000000000000000000000000000000000000000000000002010.9999999999 +2011,900000000000000000000000000000000000000000000000000000000000002011.9999999999 +2012,900000000000000000000000000000000000000000000000000000000000002012.9999999999 +2013,900000000000000000000000000000000000000000000000000000000000002013.9999999999 +2014,900000000000000000000000000000000000000000000000000000000000002014.9999999999 +2015,900000000000000000000000000000000000000000000000000000000000002015.9999999999 +2016,900000000000000000000000000000000000000000000000000000000000002016.9999999999 +2017,900000000000000000000000000000000000000000000000000000000000002017.9999999999 +2018,900000000000000000000000000000000000000000000000000000000000002018.9999999999 +2019,900000000000000000000000000000000000000000000000000000000000002019.9999999999 +2020,900000000000000000000000000000000000000000000000000000000000002020.9999999999 +2021,900000000000000000000000000000000000000000000000000000000000002021.9999999999 +2022,900000000000000000000000000000000000000000000000000000000000002022.9999999999 +2023,900000000000000000000000000000000000000000000000000000000000002023.9999999999 +2024,900000000000000000000000000000000000000000000000000000000000002024.9999999999 +2025,900000000000000000000000000000000000000000000000000000000000002025.9999999999 +2026,900000000000000000000000000000000000000000000000000000000000002026.9999999999 +2027,900000000000000000000000000000000000000000000000000000000000002027.9999999999 +2028,900000000000000000000000000000000000000000000000000000000000002028.9999999999 +2029,900000000000000000000000000000000000000000000000000000000000002029.9999999999 +2030,900000000000000000000000000000000000000000000000000000000000002030.9999999999 +2031,900000000000000000000000000000000000000000000000000000000000002031.9999999999 +2032,900000000000000000000000000000000000000000000000000000000000002032.9999999999 +2033,900000000000000000000000000000000000000000000000000000000000002033.9999999999 +2034,900000000000000000000000000000000000000000000000000000000000002034.9999999999 +2035,900000000000000000000000000000000000000000000000000000000000002035.9999999999 +2036,900000000000000000000000000000000000000000000000000000000000002036.9999999999 +2037,900000000000000000000000000000000000000000000000000000000000002037.9999999999 +2038,900000000000000000000000000000000000000000000000000000000000002038.9999999999 +2039,900000000000000000000000000000000000000000000000000000000000002039.9999999999 +2040,900000000000000000000000000000000000000000000000000000000000002040.9999999999 +2041,900000000000000000000000000000000000000000000000000000000000002041.9999999999 +2042,900000000000000000000000000000000000000000000000000000000000002042.9999999999 +2043,900000000000000000000000000000000000000000000000000000000000002043.9999999999 +2044,900000000000000000000000000000000000000000000000000000000000002044.9999999999 +2045,900000000000000000000000000000000000000000000000000000000000002045.9999999999 +2046,900000000000000000000000000000000000000000000000000000000000002046.9999999999 +2047,900000000000000000000000000000000000000000000000000000000000002047.9999999999 +2048,900000000000000000000000000000000000000000000000000000000000002048.9999999999 +2049,900000000000000000000000000000000000000000000000000000000000002049.9999999999 +2050,900000000000000000000000000000000000000000000000000000000000002050.9999999999 +2051,900000000000000000000000000000000000000000000000000000000000002051.9999999999 +2052,900000000000000000000000000000000000000000000000000000000000002052.9999999999 +2053,900000000000000000000000000000000000000000000000000000000000002053.9999999999 +2054,900000000000000000000000000000000000000000000000000000000000002054.9999999999 +2055,900000000000000000000000000000000000000000000000000000000000002055.9999999999 +2056,900000000000000000000000000000000000000000000000000000000000002056.9999999999 +2057,900000000000000000000000000000000000000000000000000000000000002057.9999999999 +2058,900000000000000000000000000000000000000000000000000000000000002058.9999999999 +2059,900000000000000000000000000000000000000000000000000000000000002059.9999999999 +2060,900000000000000000000000000000000000000000000000000000000000002060.9999999999 +2061,900000000000000000000000000000000000000000000000000000000000002061.9999999999 +2062,900000000000000000000000000000000000000000000000000000000000002062.9999999999 +2063,900000000000000000000000000000000000000000000000000000000000002063.9999999999 +2064,900000000000000000000000000000000000000000000000000000000000002064.9999999999 +2065,900000000000000000000000000000000000000000000000000000000000002065.9999999999 +2066,900000000000000000000000000000000000000000000000000000000000002066.9999999999 +2067,900000000000000000000000000000000000000000000000000000000000002067.9999999999 +2068,900000000000000000000000000000000000000000000000000000000000002068.9999999999 +2069,900000000000000000000000000000000000000000000000000000000000002069.9999999999 +2070,900000000000000000000000000000000000000000000000000000000000002070.9999999999 +2071,900000000000000000000000000000000000000000000000000000000000002071.9999999999 +2072,900000000000000000000000000000000000000000000000000000000000002072.9999999999 +2073,900000000000000000000000000000000000000000000000000000000000002073.9999999999 +2074,900000000000000000000000000000000000000000000000000000000000002074.9999999999 +2075,900000000000000000000000000000000000000000000000000000000000002075.9999999999 +2076,900000000000000000000000000000000000000000000000000000000000002076.9999999999 +2077,900000000000000000000000000000000000000000000000000000000000002077.9999999999 +2078,900000000000000000000000000000000000000000000000000000000000002078.9999999999 +2079,900000000000000000000000000000000000000000000000000000000000002079.9999999999 +2080,900000000000000000000000000000000000000000000000000000000000002080.9999999999 +2081,900000000000000000000000000000000000000000000000000000000000002081.9999999999 +2082,900000000000000000000000000000000000000000000000000000000000002082.9999999999 +2083,900000000000000000000000000000000000000000000000000000000000002083.9999999999 +2084,900000000000000000000000000000000000000000000000000000000000002084.9999999999 +2085,900000000000000000000000000000000000000000000000000000000000002085.9999999999 +2086,900000000000000000000000000000000000000000000000000000000000002086.9999999999 +2087,900000000000000000000000000000000000000000000000000000000000002087.9999999999 +2088,900000000000000000000000000000000000000000000000000000000000002088.9999999999 +2089,900000000000000000000000000000000000000000000000000000000000002089.9999999999 +2090,900000000000000000000000000000000000000000000000000000000000002090.9999999999 +2091,900000000000000000000000000000000000000000000000000000000000002091.9999999999 +2092,900000000000000000000000000000000000000000000000000000000000002092.9999999999 +2093,900000000000000000000000000000000000000000000000000000000000002093.9999999999 +2094,900000000000000000000000000000000000000000000000000000000000002094.9999999999 +2095,900000000000000000000000000000000000000000000000000000000000002095.9999999999 +2096,900000000000000000000000000000000000000000000000000000000000002096.9999999999 +2097,900000000000000000000000000000000000000000000000000000000000002097.9999999999 +2098,900000000000000000000000000000000000000000000000000000000000002098.9999999999 +2099,900000000000000000000000000000000000000000000000000000000000002099.9999999999 +2100,900000000000000000000000000000000000000000000000000000000000002100.9999999999 +2101,900000000000000000000000000000000000000000000000000000000000002101.9999999999 +2102,900000000000000000000000000000000000000000000000000000000000002102.9999999999 +2103,900000000000000000000000000000000000000000000000000000000000002103.9999999999 +2104,900000000000000000000000000000000000000000000000000000000000002104.9999999999 +2105,900000000000000000000000000000000000000000000000000000000000002105.9999999999 +2106,900000000000000000000000000000000000000000000000000000000000002106.9999999999 +2107,900000000000000000000000000000000000000000000000000000000000002107.9999999999 +2108,900000000000000000000000000000000000000000000000000000000000002108.9999999999 +2109,900000000000000000000000000000000000000000000000000000000000002109.9999999999 +2110,900000000000000000000000000000000000000000000000000000000000002110.9999999999 +2111,900000000000000000000000000000000000000000000000000000000000002111.9999999999 +2112,900000000000000000000000000000000000000000000000000000000000002112.9999999999 +2113,900000000000000000000000000000000000000000000000000000000000002113.9999999999 +2114,900000000000000000000000000000000000000000000000000000000000002114.9999999999 +2115,900000000000000000000000000000000000000000000000000000000000002115.9999999999 +2116,900000000000000000000000000000000000000000000000000000000000002116.9999999999 +2117,900000000000000000000000000000000000000000000000000000000000002117.9999999999 +2118,900000000000000000000000000000000000000000000000000000000000002118.9999999999 +2119,900000000000000000000000000000000000000000000000000000000000002119.9999999999 +2120,900000000000000000000000000000000000000000000000000000000000002120.9999999999 +2121,900000000000000000000000000000000000000000000000000000000000002121.9999999999 +2122,900000000000000000000000000000000000000000000000000000000000002122.9999999999 +2123,900000000000000000000000000000000000000000000000000000000000002123.9999999999 +2124,900000000000000000000000000000000000000000000000000000000000002124.9999999999 +2125,900000000000000000000000000000000000000000000000000000000000002125.9999999999 +2126,900000000000000000000000000000000000000000000000000000000000002126.9999999999 +2127,900000000000000000000000000000000000000000000000000000000000002127.9999999999 +2128,900000000000000000000000000000000000000000000000000000000000002128.9999999999 +2129,900000000000000000000000000000000000000000000000000000000000002129.9999999999 +2130,900000000000000000000000000000000000000000000000000000000000002130.9999999999 +2131,900000000000000000000000000000000000000000000000000000000000002131.9999999999 +2132,900000000000000000000000000000000000000000000000000000000000002132.9999999999 +2133,900000000000000000000000000000000000000000000000000000000000002133.9999999999 +2134,900000000000000000000000000000000000000000000000000000000000002134.9999999999 +2135,900000000000000000000000000000000000000000000000000000000000002135.9999999999 +2136,900000000000000000000000000000000000000000000000000000000000002136.9999999999 +2137,900000000000000000000000000000000000000000000000000000000000002137.9999999999 +2138,900000000000000000000000000000000000000000000000000000000000002138.9999999999 +2139,900000000000000000000000000000000000000000000000000000000000002139.9999999999 +2140,900000000000000000000000000000000000000000000000000000000000002140.9999999999 +2141,900000000000000000000000000000000000000000000000000000000000002141.9999999999 +2142,900000000000000000000000000000000000000000000000000000000000002142.9999999999 +2143,900000000000000000000000000000000000000000000000000000000000002143.9999999999 +2144,900000000000000000000000000000000000000000000000000000000000002144.9999999999 +2145,900000000000000000000000000000000000000000000000000000000000002145.9999999999 +2146,900000000000000000000000000000000000000000000000000000000000002146.9999999999 +2147,900000000000000000000000000000000000000000000000000000000000002147.9999999999 +2148,900000000000000000000000000000000000000000000000000000000000002148.9999999999 +2149,900000000000000000000000000000000000000000000000000000000000002149.9999999999 +2150,900000000000000000000000000000000000000000000000000000000000002150.9999999999 +2151,900000000000000000000000000000000000000000000000000000000000002151.9999999999 +2152,900000000000000000000000000000000000000000000000000000000000002152.9999999999 +2153,900000000000000000000000000000000000000000000000000000000000002153.9999999999 +2154,900000000000000000000000000000000000000000000000000000000000002154.9999999999 +2155,900000000000000000000000000000000000000000000000000000000000002155.9999999999 +2156,900000000000000000000000000000000000000000000000000000000000002156.9999999999 +2157,900000000000000000000000000000000000000000000000000000000000002157.9999999999 +2158,900000000000000000000000000000000000000000000000000000000000002158.9999999999 +2159,900000000000000000000000000000000000000000000000000000000000002159.9999999999 +2160,900000000000000000000000000000000000000000000000000000000000002160.9999999999 +2161,900000000000000000000000000000000000000000000000000000000000002161.9999999999 +2162,900000000000000000000000000000000000000000000000000000000000002162.9999999999 +2163,900000000000000000000000000000000000000000000000000000000000002163.9999999999 +2164,900000000000000000000000000000000000000000000000000000000000002164.9999999999 +2165,900000000000000000000000000000000000000000000000000000000000002165.9999999999 +2166,900000000000000000000000000000000000000000000000000000000000002166.9999999999 +2167,900000000000000000000000000000000000000000000000000000000000002167.9999999999 +2168,900000000000000000000000000000000000000000000000000000000000002168.9999999999 +2169,900000000000000000000000000000000000000000000000000000000000002169.9999999999 +2170,900000000000000000000000000000000000000000000000000000000000002170.9999999999 +2171,900000000000000000000000000000000000000000000000000000000000002171.9999999999 +2172,900000000000000000000000000000000000000000000000000000000000002172.9999999999 +2173,900000000000000000000000000000000000000000000000000000000000002173.9999999999 +2174,900000000000000000000000000000000000000000000000000000000000002174.9999999999 +2175,900000000000000000000000000000000000000000000000000000000000002175.9999999999 +2176,900000000000000000000000000000000000000000000000000000000000002176.9999999999 +2177,900000000000000000000000000000000000000000000000000000000000002177.9999999999 +2178,900000000000000000000000000000000000000000000000000000000000002178.9999999999 +2179,900000000000000000000000000000000000000000000000000000000000002179.9999999999 +2180,900000000000000000000000000000000000000000000000000000000000002180.9999999999 +2181,900000000000000000000000000000000000000000000000000000000000002181.9999999999 +2182,900000000000000000000000000000000000000000000000000000000000002182.9999999999 +2183,900000000000000000000000000000000000000000000000000000000000002183.9999999999 +2184,900000000000000000000000000000000000000000000000000000000000002184.9999999999 +2185,900000000000000000000000000000000000000000000000000000000000002185.9999999999 +2186,900000000000000000000000000000000000000000000000000000000000002186.9999999999 +2187,900000000000000000000000000000000000000000000000000000000000002187.9999999999 +2188,900000000000000000000000000000000000000000000000000000000000002188.9999999999 +2189,900000000000000000000000000000000000000000000000000000000000002189.9999999999 +2190,900000000000000000000000000000000000000000000000000000000000002190.9999999999 +2191,900000000000000000000000000000000000000000000000000000000000002191.9999999999 +2192,900000000000000000000000000000000000000000000000000000000000002192.9999999999 +2193,900000000000000000000000000000000000000000000000000000000000002193.9999999999 +2194,900000000000000000000000000000000000000000000000000000000000002194.9999999999 +2195,900000000000000000000000000000000000000000000000000000000000002195.9999999999 +2196,900000000000000000000000000000000000000000000000000000000000002196.9999999999 +2197,900000000000000000000000000000000000000000000000000000000000002197.9999999999 +2198,900000000000000000000000000000000000000000000000000000000000002198.9999999999 +2199,900000000000000000000000000000000000000000000000000000000000002199.9999999999 +2200,900000000000000000000000000000000000000000000000000000000000002200.9999999999 +2201,900000000000000000000000000000000000000000000000000000000000002201.9999999999 +2202,900000000000000000000000000000000000000000000000000000000000002202.9999999999 +2203,900000000000000000000000000000000000000000000000000000000000002203.9999999999 +2204,900000000000000000000000000000000000000000000000000000000000002204.9999999999 +2205,900000000000000000000000000000000000000000000000000000000000002205.9999999999 +2206,900000000000000000000000000000000000000000000000000000000000002206.9999999999 +2207,900000000000000000000000000000000000000000000000000000000000002207.9999999999 +2208,900000000000000000000000000000000000000000000000000000000000002208.9999999999 +2209,900000000000000000000000000000000000000000000000000000000000002209.9999999999 +2210,900000000000000000000000000000000000000000000000000000000000002210.9999999999 +2211,900000000000000000000000000000000000000000000000000000000000002211.9999999999 +2212,900000000000000000000000000000000000000000000000000000000000002212.9999999999 +2213,900000000000000000000000000000000000000000000000000000000000002213.9999999999 +2214,900000000000000000000000000000000000000000000000000000000000002214.9999999999 +2215,900000000000000000000000000000000000000000000000000000000000002215.9999999999 +2216,900000000000000000000000000000000000000000000000000000000000002216.9999999999 +2217,900000000000000000000000000000000000000000000000000000000000002217.9999999999 +2218,900000000000000000000000000000000000000000000000000000000000002218.9999999999 +2219,900000000000000000000000000000000000000000000000000000000000002219.9999999999 +2220,900000000000000000000000000000000000000000000000000000000000002220.9999999999 +2221,900000000000000000000000000000000000000000000000000000000000002221.9999999999 +2222,900000000000000000000000000000000000000000000000000000000000002222.9999999999 +2223,900000000000000000000000000000000000000000000000000000000000002223.9999999999 +2224,900000000000000000000000000000000000000000000000000000000000002224.9999999999 +2225,900000000000000000000000000000000000000000000000000000000000002225.9999999999 +2226,900000000000000000000000000000000000000000000000000000000000002226.9999999999 +2227,900000000000000000000000000000000000000000000000000000000000002227.9999999999 +2228,900000000000000000000000000000000000000000000000000000000000002228.9999999999 +2229,900000000000000000000000000000000000000000000000000000000000002229.9999999999 +2230,900000000000000000000000000000000000000000000000000000000000002230.9999999999 +2231,900000000000000000000000000000000000000000000000000000000000002231.9999999999 +2232,900000000000000000000000000000000000000000000000000000000000002232.9999999999 +2233,900000000000000000000000000000000000000000000000000000000000002233.9999999999 +2234,900000000000000000000000000000000000000000000000000000000000002234.9999999999 +2235,900000000000000000000000000000000000000000000000000000000000002235.9999999999 +2236,900000000000000000000000000000000000000000000000000000000000002236.9999999999 +2237,900000000000000000000000000000000000000000000000000000000000002237.9999999999 +2238,900000000000000000000000000000000000000000000000000000000000002238.9999999999 +2239,900000000000000000000000000000000000000000000000000000000000002239.9999999999 +2240,900000000000000000000000000000000000000000000000000000000000002240.9999999999 +2241,900000000000000000000000000000000000000000000000000000000000002241.9999999999 +2242,900000000000000000000000000000000000000000000000000000000000002242.9999999999 +2243,900000000000000000000000000000000000000000000000000000000000002243.9999999999 +2244,900000000000000000000000000000000000000000000000000000000000002244.9999999999 +2245,900000000000000000000000000000000000000000000000000000000000002245.9999999999 +2246,900000000000000000000000000000000000000000000000000000000000002246.9999999999 +2247,900000000000000000000000000000000000000000000000000000000000002247.9999999999 +2248,900000000000000000000000000000000000000000000000000000000000002248.9999999999 +2249,900000000000000000000000000000000000000000000000000000000000002249.9999999999 +2250,900000000000000000000000000000000000000000000000000000000000002250.9999999999 +2251,900000000000000000000000000000000000000000000000000000000000002251.9999999999 +2252,900000000000000000000000000000000000000000000000000000000000002252.9999999999 +2253,900000000000000000000000000000000000000000000000000000000000002253.9999999999 +2254,900000000000000000000000000000000000000000000000000000000000002254.9999999999 +2255,900000000000000000000000000000000000000000000000000000000000002255.9999999999 +2256,900000000000000000000000000000000000000000000000000000000000002256.9999999999 +2257,900000000000000000000000000000000000000000000000000000000000002257.9999999999 +2258,900000000000000000000000000000000000000000000000000000000000002258.9999999999 +2259,900000000000000000000000000000000000000000000000000000000000002259.9999999999 +2260,900000000000000000000000000000000000000000000000000000000000002260.9999999999 +2261,900000000000000000000000000000000000000000000000000000000000002261.9999999999 +2262,900000000000000000000000000000000000000000000000000000000000002262.9999999999 +2263,900000000000000000000000000000000000000000000000000000000000002263.9999999999 +2264,900000000000000000000000000000000000000000000000000000000000002264.9999999999 +2265,900000000000000000000000000000000000000000000000000000000000002265.9999999999 +2266,900000000000000000000000000000000000000000000000000000000000002266.9999999999 +2267,900000000000000000000000000000000000000000000000000000000000002267.9999999999 +2268,900000000000000000000000000000000000000000000000000000000000002268.9999999999 +2269,900000000000000000000000000000000000000000000000000000000000002269.9999999999 +2270,900000000000000000000000000000000000000000000000000000000000002270.9999999999 +2271,900000000000000000000000000000000000000000000000000000000000002271.9999999999 +2272,900000000000000000000000000000000000000000000000000000000000002272.9999999999 +2273,900000000000000000000000000000000000000000000000000000000000002273.9999999999 +2274,900000000000000000000000000000000000000000000000000000000000002274.9999999999 +2275,900000000000000000000000000000000000000000000000000000000000002275.9999999999 +2276,900000000000000000000000000000000000000000000000000000000000002276.9999999999 +2277,900000000000000000000000000000000000000000000000000000000000002277.9999999999 +2278,900000000000000000000000000000000000000000000000000000000000002278.9999999999 +2279,900000000000000000000000000000000000000000000000000000000000002279.9999999999 +2280,900000000000000000000000000000000000000000000000000000000000002280.9999999999 +2281,900000000000000000000000000000000000000000000000000000000000002281.9999999999 +2282,900000000000000000000000000000000000000000000000000000000000002282.9999999999 +2283,900000000000000000000000000000000000000000000000000000000000002283.9999999999 +2284,900000000000000000000000000000000000000000000000000000000000002284.9999999999 +2285,900000000000000000000000000000000000000000000000000000000000002285.9999999999 +2286,900000000000000000000000000000000000000000000000000000000000002286.9999999999 +2287,900000000000000000000000000000000000000000000000000000000000002287.9999999999 +2288,900000000000000000000000000000000000000000000000000000000000002288.9999999999 +2289,900000000000000000000000000000000000000000000000000000000000002289.9999999999 +2290,900000000000000000000000000000000000000000000000000000000000002290.9999999999 +2291,900000000000000000000000000000000000000000000000000000000000002291.9999999999 +2292,900000000000000000000000000000000000000000000000000000000000002292.9999999999 +2293,900000000000000000000000000000000000000000000000000000000000002293.9999999999 +2294,900000000000000000000000000000000000000000000000000000000000002294.9999999999 +2295,900000000000000000000000000000000000000000000000000000000000002295.9999999999 +2296,900000000000000000000000000000000000000000000000000000000000002296.9999999999 +2297,900000000000000000000000000000000000000000000000000000000000002297.9999999999 +2298,900000000000000000000000000000000000000000000000000000000000002298.9999999999 +2299,900000000000000000000000000000000000000000000000000000000000002299.9999999999 +2300,900000000000000000000000000000000000000000000000000000000000002300.9999999999 +2301,900000000000000000000000000000000000000000000000000000000000002301.9999999999 +2302,900000000000000000000000000000000000000000000000000000000000002302.9999999999 +2303,900000000000000000000000000000000000000000000000000000000000002303.9999999999 +2304,900000000000000000000000000000000000000000000000000000000000002304.9999999999 +2305,900000000000000000000000000000000000000000000000000000000000002305.9999999999 +2306,900000000000000000000000000000000000000000000000000000000000002306.9999999999 +2307,900000000000000000000000000000000000000000000000000000000000002307.9999999999 +2308,900000000000000000000000000000000000000000000000000000000000002308.9999999999 +2309,900000000000000000000000000000000000000000000000000000000000002309.9999999999 +2310,900000000000000000000000000000000000000000000000000000000000002310.9999999999 +2311,900000000000000000000000000000000000000000000000000000000000002311.9999999999 +2312,900000000000000000000000000000000000000000000000000000000000002312.9999999999 +2313,900000000000000000000000000000000000000000000000000000000000002313.9999999999 +2314,900000000000000000000000000000000000000000000000000000000000002314.9999999999 +2315,900000000000000000000000000000000000000000000000000000000000002315.9999999999 +2316,900000000000000000000000000000000000000000000000000000000000002316.9999999999 +2317,900000000000000000000000000000000000000000000000000000000000002317.9999999999 +2318,900000000000000000000000000000000000000000000000000000000000002318.9999999999 +2319,900000000000000000000000000000000000000000000000000000000000002319.9999999999 +2320,900000000000000000000000000000000000000000000000000000000000002320.9999999999 +2321,900000000000000000000000000000000000000000000000000000000000002321.9999999999 +2322,900000000000000000000000000000000000000000000000000000000000002322.9999999999 +2323,900000000000000000000000000000000000000000000000000000000000002323.9999999999 +2324,900000000000000000000000000000000000000000000000000000000000002324.9999999999 +2325,900000000000000000000000000000000000000000000000000000000000002325.9999999999 +2326,900000000000000000000000000000000000000000000000000000000000002326.9999999999 +2327,900000000000000000000000000000000000000000000000000000000000002327.9999999999 +2328,900000000000000000000000000000000000000000000000000000000000002328.9999999999 +2329,900000000000000000000000000000000000000000000000000000000000002329.9999999999 +2330,900000000000000000000000000000000000000000000000000000000000002330.9999999999 +2331,900000000000000000000000000000000000000000000000000000000000002331.9999999999 +2332,900000000000000000000000000000000000000000000000000000000000002332.9999999999 +2333,900000000000000000000000000000000000000000000000000000000000002333.9999999999 +2334,900000000000000000000000000000000000000000000000000000000000002334.9999999999 +2335,900000000000000000000000000000000000000000000000000000000000002335.9999999999 +2336,900000000000000000000000000000000000000000000000000000000000002336.9999999999 +2337,900000000000000000000000000000000000000000000000000000000000002337.9999999999 +2338,900000000000000000000000000000000000000000000000000000000000002338.9999999999 +2339,900000000000000000000000000000000000000000000000000000000000002339.9999999999 +2340,900000000000000000000000000000000000000000000000000000000000002340.9999999999 +2341,900000000000000000000000000000000000000000000000000000000000002341.9999999999 +2342,900000000000000000000000000000000000000000000000000000000000002342.9999999999 +2343,900000000000000000000000000000000000000000000000000000000000002343.9999999999 +2344,900000000000000000000000000000000000000000000000000000000000002344.9999999999 +2345,900000000000000000000000000000000000000000000000000000000000002345.9999999999 +2346,900000000000000000000000000000000000000000000000000000000000002346.9999999999 +2347,900000000000000000000000000000000000000000000000000000000000002347.9999999999 +2348,900000000000000000000000000000000000000000000000000000000000002348.9999999999 +2349,900000000000000000000000000000000000000000000000000000000000002349.9999999999 +2350,900000000000000000000000000000000000000000000000000000000000002350.9999999999 +2351,900000000000000000000000000000000000000000000000000000000000002351.9999999999 +2352,900000000000000000000000000000000000000000000000000000000000002352.9999999999 +2353,900000000000000000000000000000000000000000000000000000000000002353.9999999999 +2354,900000000000000000000000000000000000000000000000000000000000002354.9999999999 +2355,900000000000000000000000000000000000000000000000000000000000002355.9999999999 +2356,900000000000000000000000000000000000000000000000000000000000002356.9999999999 +2357,900000000000000000000000000000000000000000000000000000000000002357.9999999999 +2358,900000000000000000000000000000000000000000000000000000000000002358.9999999999 +2359,900000000000000000000000000000000000000000000000000000000000002359.9999999999 +2360,900000000000000000000000000000000000000000000000000000000000002360.9999999999 +2361,900000000000000000000000000000000000000000000000000000000000002361.9999999999 +2362,900000000000000000000000000000000000000000000000000000000000002362.9999999999 +2363,900000000000000000000000000000000000000000000000000000000000002363.9999999999 +2364,900000000000000000000000000000000000000000000000000000000000002364.9999999999 +2365,900000000000000000000000000000000000000000000000000000000000002365.9999999999 +2366,900000000000000000000000000000000000000000000000000000000000002366.9999999999 +2367,900000000000000000000000000000000000000000000000000000000000002367.9999999999 +2368,900000000000000000000000000000000000000000000000000000000000002368.9999999999 +2369,900000000000000000000000000000000000000000000000000000000000002369.9999999999 +2370,900000000000000000000000000000000000000000000000000000000000002370.9999999999 +2371,900000000000000000000000000000000000000000000000000000000000002371.9999999999 +2372,900000000000000000000000000000000000000000000000000000000000002372.9999999999 +2373,900000000000000000000000000000000000000000000000000000000000002373.9999999999 +2374,900000000000000000000000000000000000000000000000000000000000002374.9999999999 +2375,900000000000000000000000000000000000000000000000000000000000002375.9999999999 +2376,900000000000000000000000000000000000000000000000000000000000002376.9999999999 +2377,900000000000000000000000000000000000000000000000000000000000002377.9999999999 +2378,900000000000000000000000000000000000000000000000000000000000002378.9999999999 +2379,900000000000000000000000000000000000000000000000000000000000002379.9999999999 +2380,900000000000000000000000000000000000000000000000000000000000002380.9999999999 +2381,900000000000000000000000000000000000000000000000000000000000002381.9999999999 +2382,900000000000000000000000000000000000000000000000000000000000002382.9999999999 +2383,900000000000000000000000000000000000000000000000000000000000002383.9999999999 +2384,900000000000000000000000000000000000000000000000000000000000002384.9999999999 +2385,900000000000000000000000000000000000000000000000000000000000002385.9999999999 +2386,900000000000000000000000000000000000000000000000000000000000002386.9999999999 +2387,900000000000000000000000000000000000000000000000000000000000002387.9999999999 +2388,900000000000000000000000000000000000000000000000000000000000002388.9999999999 +2389,900000000000000000000000000000000000000000000000000000000000002389.9999999999 +2390,900000000000000000000000000000000000000000000000000000000000002390.9999999999 +2391,900000000000000000000000000000000000000000000000000000000000002391.9999999999 +2392,900000000000000000000000000000000000000000000000000000000000002392.9999999999 +2393,900000000000000000000000000000000000000000000000000000000000002393.9999999999 +2394,900000000000000000000000000000000000000000000000000000000000002394.9999999999 +2395,900000000000000000000000000000000000000000000000000000000000002395.9999999999 +2396,900000000000000000000000000000000000000000000000000000000000002396.9999999999 +2397,900000000000000000000000000000000000000000000000000000000000002397.9999999999 +2398,900000000000000000000000000000000000000000000000000000000000002398.9999999999 +2399,900000000000000000000000000000000000000000000000000000000000002399.9999999999 +2400,900000000000000000000000000000000000000000000000000000000000002400.9999999999 +2401,900000000000000000000000000000000000000000000000000000000000002401.9999999999 +2402,900000000000000000000000000000000000000000000000000000000000002402.9999999999 +2403,900000000000000000000000000000000000000000000000000000000000002403.9999999999 +2404,900000000000000000000000000000000000000000000000000000000000002404.9999999999 +2405,900000000000000000000000000000000000000000000000000000000000002405.9999999999 +2406,900000000000000000000000000000000000000000000000000000000000002406.9999999999 +2407,900000000000000000000000000000000000000000000000000000000000002407.9999999999 +2408,900000000000000000000000000000000000000000000000000000000000002408.9999999999 +2409,900000000000000000000000000000000000000000000000000000000000002409.9999999999 +2410,900000000000000000000000000000000000000000000000000000000000002410.9999999999 +2411,900000000000000000000000000000000000000000000000000000000000002411.9999999999 +2412,900000000000000000000000000000000000000000000000000000000000002412.9999999999 +2413,900000000000000000000000000000000000000000000000000000000000002413.9999999999 +2414,900000000000000000000000000000000000000000000000000000000000002414.9999999999 +2415,900000000000000000000000000000000000000000000000000000000000002415.9999999999 +2416,900000000000000000000000000000000000000000000000000000000000002416.9999999999 +2417,900000000000000000000000000000000000000000000000000000000000002417.9999999999 +2418,900000000000000000000000000000000000000000000000000000000000002418.9999999999 +2419,900000000000000000000000000000000000000000000000000000000000002419.9999999999 +2420,900000000000000000000000000000000000000000000000000000000000002420.9999999999 +2421,900000000000000000000000000000000000000000000000000000000000002421.9999999999 +2422,900000000000000000000000000000000000000000000000000000000000002422.9999999999 +2423,900000000000000000000000000000000000000000000000000000000000002423.9999999999 +2424,900000000000000000000000000000000000000000000000000000000000002424.9999999999 +2425,900000000000000000000000000000000000000000000000000000000000002425.9999999999 +2426,900000000000000000000000000000000000000000000000000000000000002426.9999999999 +2427,900000000000000000000000000000000000000000000000000000000000002427.9999999999 +2428,900000000000000000000000000000000000000000000000000000000000002428.9999999999 +2429,900000000000000000000000000000000000000000000000000000000000002429.9999999999 +2430,900000000000000000000000000000000000000000000000000000000000002430.9999999999 +2431,900000000000000000000000000000000000000000000000000000000000002431.9999999999 +2432,900000000000000000000000000000000000000000000000000000000000002432.9999999999 +2433,900000000000000000000000000000000000000000000000000000000000002433.9999999999 +2434,900000000000000000000000000000000000000000000000000000000000002434.9999999999 +2435,900000000000000000000000000000000000000000000000000000000000002435.9999999999 +2436,900000000000000000000000000000000000000000000000000000000000002436.9999999999 +2437,900000000000000000000000000000000000000000000000000000000000002437.9999999999 +2438,900000000000000000000000000000000000000000000000000000000000002438.9999999999 +2439,900000000000000000000000000000000000000000000000000000000000002439.9999999999 +2440,900000000000000000000000000000000000000000000000000000000000002440.9999999999 +2441,900000000000000000000000000000000000000000000000000000000000002441.9999999999 +2442,900000000000000000000000000000000000000000000000000000000000002442.9999999999 +2443,900000000000000000000000000000000000000000000000000000000000002443.9999999999 +2444,900000000000000000000000000000000000000000000000000000000000002444.9999999999 +2445,900000000000000000000000000000000000000000000000000000000000002445.9999999999 +2446,900000000000000000000000000000000000000000000000000000000000002446.9999999999 +2447,900000000000000000000000000000000000000000000000000000000000002447.9999999999 +2448,900000000000000000000000000000000000000000000000000000000000002448.9999999999 +2449,900000000000000000000000000000000000000000000000000000000000002449.9999999999 +2450,900000000000000000000000000000000000000000000000000000000000002450.9999999999 +2451,900000000000000000000000000000000000000000000000000000000000002451.9999999999 +2452,900000000000000000000000000000000000000000000000000000000000002452.9999999999 +2453,900000000000000000000000000000000000000000000000000000000000002453.9999999999 +2454,900000000000000000000000000000000000000000000000000000000000002454.9999999999 +2455,900000000000000000000000000000000000000000000000000000000000002455.9999999999 +2456,900000000000000000000000000000000000000000000000000000000000002456.9999999999 +2457,900000000000000000000000000000000000000000000000000000000000002457.9999999999 +2458,900000000000000000000000000000000000000000000000000000000000002458.9999999999 +2459,900000000000000000000000000000000000000000000000000000000000002459.9999999999 +2460,900000000000000000000000000000000000000000000000000000000000002460.9999999999 +2461,900000000000000000000000000000000000000000000000000000000000002461.9999999999 +2462,900000000000000000000000000000000000000000000000000000000000002462.9999999999 +2463,900000000000000000000000000000000000000000000000000000000000002463.9999999999 +2464,900000000000000000000000000000000000000000000000000000000000002464.9999999999 +2465,900000000000000000000000000000000000000000000000000000000000002465.9999999999 +2466,900000000000000000000000000000000000000000000000000000000000002466.9999999999 +2467,900000000000000000000000000000000000000000000000000000000000002467.9999999999 +2468,900000000000000000000000000000000000000000000000000000000000002468.9999999999 +2469,900000000000000000000000000000000000000000000000000000000000002469.9999999999 +2470,900000000000000000000000000000000000000000000000000000000000002470.9999999999 +2471,900000000000000000000000000000000000000000000000000000000000002471.9999999999 +2472,900000000000000000000000000000000000000000000000000000000000002472.9999999999 +2473,900000000000000000000000000000000000000000000000000000000000002473.9999999999 +2474,900000000000000000000000000000000000000000000000000000000000002474.9999999999 +2475,900000000000000000000000000000000000000000000000000000000000002475.9999999999 +2476,900000000000000000000000000000000000000000000000000000000000002476.9999999999 +2477,900000000000000000000000000000000000000000000000000000000000002477.9999999999 +2478,900000000000000000000000000000000000000000000000000000000000002478.9999999999 +2479,900000000000000000000000000000000000000000000000000000000000002479.9999999999 +2480,900000000000000000000000000000000000000000000000000000000000002480.9999999999 +2481,900000000000000000000000000000000000000000000000000000000000002481.9999999999 +2482,900000000000000000000000000000000000000000000000000000000000002482.9999999999 +2483,900000000000000000000000000000000000000000000000000000000000002483.9999999999 +2484,900000000000000000000000000000000000000000000000000000000000002484.9999999999 +2485,900000000000000000000000000000000000000000000000000000000000002485.9999999999 +2486,900000000000000000000000000000000000000000000000000000000000002486.9999999999 +2487,900000000000000000000000000000000000000000000000000000000000002487.9999999999 +2488,900000000000000000000000000000000000000000000000000000000000002488.9999999999 +2489,900000000000000000000000000000000000000000000000000000000000002489.9999999999 +2490,900000000000000000000000000000000000000000000000000000000000002490.9999999999 +2491,900000000000000000000000000000000000000000000000000000000000002491.9999999999 +2492,900000000000000000000000000000000000000000000000000000000000002492.9999999999 +2493,900000000000000000000000000000000000000000000000000000000000002493.9999999999 +2494,900000000000000000000000000000000000000000000000000000000000002494.9999999999 +2495,900000000000000000000000000000000000000000000000000000000000002495.9999999999 +2496,900000000000000000000000000000000000000000000000000000000000002496.9999999999 +2497,900000000000000000000000000000000000000000000000000000000000002497.9999999999 +2498,900000000000000000000000000000000000000000000000000000000000002498.9999999999 +2499,900000000000000000000000000000000000000000000000000000000000002499.9999999999 +2500,900000000000000000000000000000000000000000000000000000000000002500.9999999999 +2501,900000000000000000000000000000000000000000000000000000000000002501.9999999999 +2502,900000000000000000000000000000000000000000000000000000000000002502.9999999999 +2503,900000000000000000000000000000000000000000000000000000000000002503.9999999999 +2504,900000000000000000000000000000000000000000000000000000000000002504.9999999999 +2505,900000000000000000000000000000000000000000000000000000000000002505.9999999999 +2506,900000000000000000000000000000000000000000000000000000000000002506.9999999999 +2507,900000000000000000000000000000000000000000000000000000000000002507.9999999999 +2508,900000000000000000000000000000000000000000000000000000000000002508.9999999999 +2509,900000000000000000000000000000000000000000000000000000000000002509.9999999999 +2510,900000000000000000000000000000000000000000000000000000000000002510.9999999999 +2511,900000000000000000000000000000000000000000000000000000000000002511.9999999999 +2512,900000000000000000000000000000000000000000000000000000000000002512.9999999999 +2513,900000000000000000000000000000000000000000000000000000000000002513.9999999999 +2514,900000000000000000000000000000000000000000000000000000000000002514.9999999999 +2515,900000000000000000000000000000000000000000000000000000000000002515.9999999999 +2516,900000000000000000000000000000000000000000000000000000000000002516.9999999999 +2517,900000000000000000000000000000000000000000000000000000000000002517.9999999999 +2518,900000000000000000000000000000000000000000000000000000000000002518.9999999999 +2519,900000000000000000000000000000000000000000000000000000000000002519.9999999999 +2520,900000000000000000000000000000000000000000000000000000000000002520.9999999999 +2521,900000000000000000000000000000000000000000000000000000000000002521.9999999999 +2522,900000000000000000000000000000000000000000000000000000000000002522.9999999999 +2523,900000000000000000000000000000000000000000000000000000000000002523.9999999999 +2524,900000000000000000000000000000000000000000000000000000000000002524.9999999999 +2525,900000000000000000000000000000000000000000000000000000000000002525.9999999999 +2526,900000000000000000000000000000000000000000000000000000000000002526.9999999999 +2527,900000000000000000000000000000000000000000000000000000000000002527.9999999999 +2528,900000000000000000000000000000000000000000000000000000000000002528.9999999999 +2529,900000000000000000000000000000000000000000000000000000000000002529.9999999999 +2530,900000000000000000000000000000000000000000000000000000000000002530.9999999999 +2531,900000000000000000000000000000000000000000000000000000000000002531.9999999999 +2532,900000000000000000000000000000000000000000000000000000000000002532.9999999999 +2533,900000000000000000000000000000000000000000000000000000000000002533.9999999999 +2534,900000000000000000000000000000000000000000000000000000000000002534.9999999999 +2535,900000000000000000000000000000000000000000000000000000000000002535.9999999999 +2536,900000000000000000000000000000000000000000000000000000000000002536.9999999999 +2537,900000000000000000000000000000000000000000000000000000000000002537.9999999999 +2538,900000000000000000000000000000000000000000000000000000000000002538.9999999999 +2539,900000000000000000000000000000000000000000000000000000000000002539.9999999999 +2540,900000000000000000000000000000000000000000000000000000000000002540.9999999999 +2541,900000000000000000000000000000000000000000000000000000000000002541.9999999999 +2542,900000000000000000000000000000000000000000000000000000000000002542.9999999999 +2543,900000000000000000000000000000000000000000000000000000000000002543.9999999999 +2544,900000000000000000000000000000000000000000000000000000000000002544.9999999999 +2545,900000000000000000000000000000000000000000000000000000000000002545.9999999999 +2546,900000000000000000000000000000000000000000000000000000000000002546.9999999999 +2547,900000000000000000000000000000000000000000000000000000000000002547.9999999999 +2548,900000000000000000000000000000000000000000000000000000000000002548.9999999999 +2549,900000000000000000000000000000000000000000000000000000000000002549.9999999999 +2550,900000000000000000000000000000000000000000000000000000000000002550.9999999999 +2551,900000000000000000000000000000000000000000000000000000000000002551.9999999999 +2552,900000000000000000000000000000000000000000000000000000000000002552.9999999999 +2553,900000000000000000000000000000000000000000000000000000000000002553.9999999999 +2554,900000000000000000000000000000000000000000000000000000000000002554.9999999999 +2555,900000000000000000000000000000000000000000000000000000000000002555.9999999999 +2556,900000000000000000000000000000000000000000000000000000000000002556.9999999999 +2557,900000000000000000000000000000000000000000000000000000000000002557.9999999999 +2558,900000000000000000000000000000000000000000000000000000000000002558.9999999999 +2559,900000000000000000000000000000000000000000000000000000000000002559.9999999999 +2560,900000000000000000000000000000000000000000000000000000000000002560.9999999999 +2561,900000000000000000000000000000000000000000000000000000000000002561.9999999999 +2562,900000000000000000000000000000000000000000000000000000000000002562.9999999999 +2563,900000000000000000000000000000000000000000000000000000000000002563.9999999999 +2564,900000000000000000000000000000000000000000000000000000000000002564.9999999999 +2565,900000000000000000000000000000000000000000000000000000000000002565.9999999999 +2566,900000000000000000000000000000000000000000000000000000000000002566.9999999999 +2567,900000000000000000000000000000000000000000000000000000000000002567.9999999999 +2568,900000000000000000000000000000000000000000000000000000000000002568.9999999999 +2569,900000000000000000000000000000000000000000000000000000000000002569.9999999999 +2570,900000000000000000000000000000000000000000000000000000000000002570.9999999999 +2571,900000000000000000000000000000000000000000000000000000000000002571.9999999999 +2572,900000000000000000000000000000000000000000000000000000000000002572.9999999999 +2573,900000000000000000000000000000000000000000000000000000000000002573.9999999999 +2574,900000000000000000000000000000000000000000000000000000000000002574.9999999999 +2575,900000000000000000000000000000000000000000000000000000000000002575.9999999999 +2576,900000000000000000000000000000000000000000000000000000000000002576.9999999999 +2577,900000000000000000000000000000000000000000000000000000000000002577.9999999999 +2578,900000000000000000000000000000000000000000000000000000000000002578.9999999999 +2579,900000000000000000000000000000000000000000000000000000000000002579.9999999999 +2580,900000000000000000000000000000000000000000000000000000000000002580.9999999999 +2581,900000000000000000000000000000000000000000000000000000000000002581.9999999999 +2582,900000000000000000000000000000000000000000000000000000000000002582.9999999999 +2583,900000000000000000000000000000000000000000000000000000000000002583.9999999999 +2584,900000000000000000000000000000000000000000000000000000000000002584.9999999999 +2585,900000000000000000000000000000000000000000000000000000000000002585.9999999999 +2586,900000000000000000000000000000000000000000000000000000000000002586.9999999999 +2587,900000000000000000000000000000000000000000000000000000000000002587.9999999999 +2588,900000000000000000000000000000000000000000000000000000000000002588.9999999999 +2589,900000000000000000000000000000000000000000000000000000000000002589.9999999999 +2590,900000000000000000000000000000000000000000000000000000000000002590.9999999999 +2591,900000000000000000000000000000000000000000000000000000000000002591.9999999999 +2592,900000000000000000000000000000000000000000000000000000000000002592.9999999999 +2593,900000000000000000000000000000000000000000000000000000000000002593.9999999999 +2594,900000000000000000000000000000000000000000000000000000000000002594.9999999999 +2595,900000000000000000000000000000000000000000000000000000000000002595.9999999999 +2596,900000000000000000000000000000000000000000000000000000000000002596.9999999999 +2597,900000000000000000000000000000000000000000000000000000000000002597.9999999999 +2598,900000000000000000000000000000000000000000000000000000000000002598.9999999999 +2599,900000000000000000000000000000000000000000000000000000000000002599.9999999999 +2600,900000000000000000000000000000000000000000000000000000000000002600.9999999999 +2601,900000000000000000000000000000000000000000000000000000000000002601.9999999999 +2602,900000000000000000000000000000000000000000000000000000000000002602.9999999999 +2603,900000000000000000000000000000000000000000000000000000000000002603.9999999999 +2604,900000000000000000000000000000000000000000000000000000000000002604.9999999999 +2605,900000000000000000000000000000000000000000000000000000000000002605.9999999999 +2606,900000000000000000000000000000000000000000000000000000000000002606.9999999999 +2607,900000000000000000000000000000000000000000000000000000000000002607.9999999999 +2608,900000000000000000000000000000000000000000000000000000000000002608.9999999999 +2609,900000000000000000000000000000000000000000000000000000000000002609.9999999999 +2610,900000000000000000000000000000000000000000000000000000000000002610.9999999999 +2611,900000000000000000000000000000000000000000000000000000000000002611.9999999999 +2612,900000000000000000000000000000000000000000000000000000000000002612.9999999999 +2613,900000000000000000000000000000000000000000000000000000000000002613.9999999999 +2614,900000000000000000000000000000000000000000000000000000000000002614.9999999999 +2615,900000000000000000000000000000000000000000000000000000000000002615.9999999999 +2616,900000000000000000000000000000000000000000000000000000000000002616.9999999999 +2617,900000000000000000000000000000000000000000000000000000000000002617.9999999999 +2618,900000000000000000000000000000000000000000000000000000000000002618.9999999999 +2619,900000000000000000000000000000000000000000000000000000000000002619.9999999999 +2620,900000000000000000000000000000000000000000000000000000000000002620.9999999999 +2621,900000000000000000000000000000000000000000000000000000000000002621.9999999999 +2622,900000000000000000000000000000000000000000000000000000000000002622.9999999999 +2623,900000000000000000000000000000000000000000000000000000000000002623.9999999999 +2624,900000000000000000000000000000000000000000000000000000000000002624.9999999999 +2625,900000000000000000000000000000000000000000000000000000000000002625.9999999999 +2626,900000000000000000000000000000000000000000000000000000000000002626.9999999999 +2627,900000000000000000000000000000000000000000000000000000000000002627.9999999999 +2628,900000000000000000000000000000000000000000000000000000000000002628.9999999999 +2629,900000000000000000000000000000000000000000000000000000000000002629.9999999999 +2630,900000000000000000000000000000000000000000000000000000000000002630.9999999999 +2631,900000000000000000000000000000000000000000000000000000000000002631.9999999999 +2632,900000000000000000000000000000000000000000000000000000000000002632.9999999999 +2633,900000000000000000000000000000000000000000000000000000000000002633.9999999999 +2634,900000000000000000000000000000000000000000000000000000000000002634.9999999999 +2635,900000000000000000000000000000000000000000000000000000000000002635.9999999999 +2636,900000000000000000000000000000000000000000000000000000000000002636.9999999999 +2637,900000000000000000000000000000000000000000000000000000000000002637.9999999999 +2638,900000000000000000000000000000000000000000000000000000000000002638.9999999999 +2639,900000000000000000000000000000000000000000000000000000000000002639.9999999999 +2640,900000000000000000000000000000000000000000000000000000000000002640.9999999999 +2641,900000000000000000000000000000000000000000000000000000000000002641.9999999999 +2642,900000000000000000000000000000000000000000000000000000000000002642.9999999999 +2643,900000000000000000000000000000000000000000000000000000000000002643.9999999999 +2644,900000000000000000000000000000000000000000000000000000000000002644.9999999999 +2645,900000000000000000000000000000000000000000000000000000000000002645.9999999999 +2646,900000000000000000000000000000000000000000000000000000000000002646.9999999999 +2647,900000000000000000000000000000000000000000000000000000000000002647.9999999999 +2648,900000000000000000000000000000000000000000000000000000000000002648.9999999999 +2649,900000000000000000000000000000000000000000000000000000000000002649.9999999999 +2650,900000000000000000000000000000000000000000000000000000000000002650.9999999999 +2651,900000000000000000000000000000000000000000000000000000000000002651.9999999999 +2652,900000000000000000000000000000000000000000000000000000000000002652.9999999999 +2653,900000000000000000000000000000000000000000000000000000000000002653.9999999999 +2654,900000000000000000000000000000000000000000000000000000000000002654.9999999999 +2655,900000000000000000000000000000000000000000000000000000000000002655.9999999999 +2656,900000000000000000000000000000000000000000000000000000000000002656.9999999999 +2657,900000000000000000000000000000000000000000000000000000000000002657.9999999999 +2658,900000000000000000000000000000000000000000000000000000000000002658.9999999999 +2659,900000000000000000000000000000000000000000000000000000000000002659.9999999999 +2660,900000000000000000000000000000000000000000000000000000000000002660.9999999999 +2661,900000000000000000000000000000000000000000000000000000000000002661.9999999999 +2662,900000000000000000000000000000000000000000000000000000000000002662.9999999999 +2663,900000000000000000000000000000000000000000000000000000000000002663.9999999999 +2664,900000000000000000000000000000000000000000000000000000000000002664.9999999999 +2665,900000000000000000000000000000000000000000000000000000000000002665.9999999999 +2666,900000000000000000000000000000000000000000000000000000000000002666.9999999999 +2667,900000000000000000000000000000000000000000000000000000000000002667.9999999999 +2668,900000000000000000000000000000000000000000000000000000000000002668.9999999999 +2669,900000000000000000000000000000000000000000000000000000000000002669.9999999999 +2670,900000000000000000000000000000000000000000000000000000000000002670.9999999999 +2671,900000000000000000000000000000000000000000000000000000000000002671.9999999999 +2672,900000000000000000000000000000000000000000000000000000000000002672.9999999999 +2673,900000000000000000000000000000000000000000000000000000000000002673.9999999999 +2674,900000000000000000000000000000000000000000000000000000000000002674.9999999999 +2675,900000000000000000000000000000000000000000000000000000000000002675.9999999999 +2676,900000000000000000000000000000000000000000000000000000000000002676.9999999999 +2677,900000000000000000000000000000000000000000000000000000000000002677.9999999999 +2678,900000000000000000000000000000000000000000000000000000000000002678.9999999999 +2679,900000000000000000000000000000000000000000000000000000000000002679.9999999999 +2680,900000000000000000000000000000000000000000000000000000000000002680.9999999999 +2681,900000000000000000000000000000000000000000000000000000000000002681.9999999999 +2682,900000000000000000000000000000000000000000000000000000000000002682.9999999999 +2683,900000000000000000000000000000000000000000000000000000000000002683.9999999999 +2684,900000000000000000000000000000000000000000000000000000000000002684.9999999999 +2685,900000000000000000000000000000000000000000000000000000000000002685.9999999999 +2686,900000000000000000000000000000000000000000000000000000000000002686.9999999999 +2687,900000000000000000000000000000000000000000000000000000000000002687.9999999999 +2688,900000000000000000000000000000000000000000000000000000000000002688.9999999999 +2689,900000000000000000000000000000000000000000000000000000000000002689.9999999999 +2690,900000000000000000000000000000000000000000000000000000000000002690.9999999999 +2691,900000000000000000000000000000000000000000000000000000000000002691.9999999999 +2692,900000000000000000000000000000000000000000000000000000000000002692.9999999999 +2693,900000000000000000000000000000000000000000000000000000000000002693.9999999999 +2694,900000000000000000000000000000000000000000000000000000000000002694.9999999999 +2695,900000000000000000000000000000000000000000000000000000000000002695.9999999999 +2696,900000000000000000000000000000000000000000000000000000000000002696.9999999999 +2697,900000000000000000000000000000000000000000000000000000000000002697.9999999999 +2698,900000000000000000000000000000000000000000000000000000000000002698.9999999999 +2699,900000000000000000000000000000000000000000000000000000000000002699.9999999999 +2700,900000000000000000000000000000000000000000000000000000000000002700.9999999999 +2701,900000000000000000000000000000000000000000000000000000000000002701.9999999999 +2702,900000000000000000000000000000000000000000000000000000000000002702.9999999999 +2703,900000000000000000000000000000000000000000000000000000000000002703.9999999999 +2704,900000000000000000000000000000000000000000000000000000000000002704.9999999999 +2705,900000000000000000000000000000000000000000000000000000000000002705.9999999999 +2706,900000000000000000000000000000000000000000000000000000000000002706.9999999999 +2707,900000000000000000000000000000000000000000000000000000000000002707.9999999999 +2708,900000000000000000000000000000000000000000000000000000000000002708.9999999999 +2709,900000000000000000000000000000000000000000000000000000000000002709.9999999999 +2710,900000000000000000000000000000000000000000000000000000000000002710.9999999999 +2711,900000000000000000000000000000000000000000000000000000000000002711.9999999999 +2712,900000000000000000000000000000000000000000000000000000000000002712.9999999999 +2713,900000000000000000000000000000000000000000000000000000000000002713.9999999999 +2714,900000000000000000000000000000000000000000000000000000000000002714.9999999999 +2715,900000000000000000000000000000000000000000000000000000000000002715.9999999999 +2716,900000000000000000000000000000000000000000000000000000000000002716.9999999999 +2717,900000000000000000000000000000000000000000000000000000000000002717.9999999999 +2718,900000000000000000000000000000000000000000000000000000000000002718.9999999999 +2719,900000000000000000000000000000000000000000000000000000000000002719.9999999999 +2720,900000000000000000000000000000000000000000000000000000000000002720.9999999999 +2721,900000000000000000000000000000000000000000000000000000000000002721.9999999999 +2722,900000000000000000000000000000000000000000000000000000000000002722.9999999999 +2723,900000000000000000000000000000000000000000000000000000000000002723.9999999999 +2724,900000000000000000000000000000000000000000000000000000000000002724.9999999999 +2725,900000000000000000000000000000000000000000000000000000000000002725.9999999999 +2726,900000000000000000000000000000000000000000000000000000000000002726.9999999999 +2727,900000000000000000000000000000000000000000000000000000000000002727.9999999999 +2728,900000000000000000000000000000000000000000000000000000000000002728.9999999999 +2729,900000000000000000000000000000000000000000000000000000000000002729.9999999999 +2730,900000000000000000000000000000000000000000000000000000000000002730.9999999999 +2731,900000000000000000000000000000000000000000000000000000000000002731.9999999999 +2732,900000000000000000000000000000000000000000000000000000000000002732.9999999999 +2733,900000000000000000000000000000000000000000000000000000000000002733.9999999999 +2734,900000000000000000000000000000000000000000000000000000000000002734.9999999999 +2735,900000000000000000000000000000000000000000000000000000000000002735.9999999999 +2736,900000000000000000000000000000000000000000000000000000000000002736.9999999999 +2737,900000000000000000000000000000000000000000000000000000000000002737.9999999999 +2738,900000000000000000000000000000000000000000000000000000000000002738.9999999999 +2739,900000000000000000000000000000000000000000000000000000000000002739.9999999999 +2740,900000000000000000000000000000000000000000000000000000000000002740.9999999999 +2741,900000000000000000000000000000000000000000000000000000000000002741.9999999999 +2742,900000000000000000000000000000000000000000000000000000000000002742.9999999999 +2743,900000000000000000000000000000000000000000000000000000000000002743.9999999999 +2744,900000000000000000000000000000000000000000000000000000000000002744.9999999999 +2745,900000000000000000000000000000000000000000000000000000000000002745.9999999999 +2746,900000000000000000000000000000000000000000000000000000000000002746.9999999999 +2747,900000000000000000000000000000000000000000000000000000000000002747.9999999999 +2748,900000000000000000000000000000000000000000000000000000000000002748.9999999999 +2749,900000000000000000000000000000000000000000000000000000000000002749.9999999999 +2750,900000000000000000000000000000000000000000000000000000000000002750.9999999999 +2751,900000000000000000000000000000000000000000000000000000000000002751.9999999999 +2752,900000000000000000000000000000000000000000000000000000000000002752.9999999999 +2753,900000000000000000000000000000000000000000000000000000000000002753.9999999999 +2754,900000000000000000000000000000000000000000000000000000000000002754.9999999999 +2755,900000000000000000000000000000000000000000000000000000000000002755.9999999999 +2756,900000000000000000000000000000000000000000000000000000000000002756.9999999999 +2757,900000000000000000000000000000000000000000000000000000000000002757.9999999999 +2758,900000000000000000000000000000000000000000000000000000000000002758.9999999999 +2759,900000000000000000000000000000000000000000000000000000000000002759.9999999999 +2760,900000000000000000000000000000000000000000000000000000000000002760.9999999999 +2761,900000000000000000000000000000000000000000000000000000000000002761.9999999999 +2762,900000000000000000000000000000000000000000000000000000000000002762.9999999999 +2763,900000000000000000000000000000000000000000000000000000000000002763.9999999999 +2764,900000000000000000000000000000000000000000000000000000000000002764.9999999999 +2765,900000000000000000000000000000000000000000000000000000000000002765.9999999999 +2766,900000000000000000000000000000000000000000000000000000000000002766.9999999999 +2767,900000000000000000000000000000000000000000000000000000000000002767.9999999999 +2768,900000000000000000000000000000000000000000000000000000000000002768.9999999999 +2769,900000000000000000000000000000000000000000000000000000000000002769.9999999999 +2770,900000000000000000000000000000000000000000000000000000000000002770.9999999999 +2771,900000000000000000000000000000000000000000000000000000000000002771.9999999999 +2772,900000000000000000000000000000000000000000000000000000000000002772.9999999999 +2773,900000000000000000000000000000000000000000000000000000000000002773.9999999999 +2774,900000000000000000000000000000000000000000000000000000000000002774.9999999999 +2775,900000000000000000000000000000000000000000000000000000000000002775.9999999999 +2776,900000000000000000000000000000000000000000000000000000000000002776.9999999999 +2777,900000000000000000000000000000000000000000000000000000000000002777.9999999999 +2778,900000000000000000000000000000000000000000000000000000000000002778.9999999999 +2779,900000000000000000000000000000000000000000000000000000000000002779.9999999999 +2780,900000000000000000000000000000000000000000000000000000000000002780.9999999999 +2781,900000000000000000000000000000000000000000000000000000000000002781.9999999999 +2782,900000000000000000000000000000000000000000000000000000000000002782.9999999999 +2783,900000000000000000000000000000000000000000000000000000000000002783.9999999999 +2784,900000000000000000000000000000000000000000000000000000000000002784.9999999999 +2785,900000000000000000000000000000000000000000000000000000000000002785.9999999999 +2786,900000000000000000000000000000000000000000000000000000000000002786.9999999999 +2787,900000000000000000000000000000000000000000000000000000000000002787.9999999999 +2788,900000000000000000000000000000000000000000000000000000000000002788.9999999999 +2789,900000000000000000000000000000000000000000000000000000000000002789.9999999999 +2790,900000000000000000000000000000000000000000000000000000000000002790.9999999999 +2791,900000000000000000000000000000000000000000000000000000000000002791.9999999999 +2792,900000000000000000000000000000000000000000000000000000000000002792.9999999999 +2793,900000000000000000000000000000000000000000000000000000000000002793.9999999999 +2794,900000000000000000000000000000000000000000000000000000000000002794.9999999999 +2795,900000000000000000000000000000000000000000000000000000000000002795.9999999999 +2796,900000000000000000000000000000000000000000000000000000000000002796.9999999999 +2797,900000000000000000000000000000000000000000000000000000000000002797.9999999999 +2798,900000000000000000000000000000000000000000000000000000000000002798.9999999999 +2799,900000000000000000000000000000000000000000000000000000000000002799.9999999999 +2800,900000000000000000000000000000000000000000000000000000000000002800.9999999999 +2801,900000000000000000000000000000000000000000000000000000000000002801.9999999999 +2802,900000000000000000000000000000000000000000000000000000000000002802.9999999999 +2803,900000000000000000000000000000000000000000000000000000000000002803.9999999999 +2804,900000000000000000000000000000000000000000000000000000000000002804.9999999999 +2805,900000000000000000000000000000000000000000000000000000000000002805.9999999999 +2806,900000000000000000000000000000000000000000000000000000000000002806.9999999999 +2807,900000000000000000000000000000000000000000000000000000000000002807.9999999999 +2808,900000000000000000000000000000000000000000000000000000000000002808.9999999999 +2809,900000000000000000000000000000000000000000000000000000000000002809.9999999999 +2810,900000000000000000000000000000000000000000000000000000000000002810.9999999999 +2811,900000000000000000000000000000000000000000000000000000000000002811.9999999999 +2812,900000000000000000000000000000000000000000000000000000000000002812.9999999999 +2813,900000000000000000000000000000000000000000000000000000000000002813.9999999999 +2814,900000000000000000000000000000000000000000000000000000000000002814.9999999999 +2815,900000000000000000000000000000000000000000000000000000000000002815.9999999999 +2816,900000000000000000000000000000000000000000000000000000000000002816.9999999999 +2817,900000000000000000000000000000000000000000000000000000000000002817.9999999999 +2818,900000000000000000000000000000000000000000000000000000000000002818.9999999999 +2819,900000000000000000000000000000000000000000000000000000000000002819.9999999999 +2820,900000000000000000000000000000000000000000000000000000000000002820.9999999999 +2821,900000000000000000000000000000000000000000000000000000000000002821.9999999999 +2822,900000000000000000000000000000000000000000000000000000000000002822.9999999999 +2823,900000000000000000000000000000000000000000000000000000000000002823.9999999999 +2824,900000000000000000000000000000000000000000000000000000000000002824.9999999999 +2825,900000000000000000000000000000000000000000000000000000000000002825.9999999999 +2826,900000000000000000000000000000000000000000000000000000000000002826.9999999999 +2827,900000000000000000000000000000000000000000000000000000000000002827.9999999999 +2828,900000000000000000000000000000000000000000000000000000000000002828.9999999999 +2829,900000000000000000000000000000000000000000000000000000000000002829.9999999999 +2830,900000000000000000000000000000000000000000000000000000000000002830.9999999999 +2831,900000000000000000000000000000000000000000000000000000000000002831.9999999999 +2832,900000000000000000000000000000000000000000000000000000000000002832.9999999999 +2833,900000000000000000000000000000000000000000000000000000000000002833.9999999999 +2834,900000000000000000000000000000000000000000000000000000000000002834.9999999999 +2835,900000000000000000000000000000000000000000000000000000000000002835.9999999999 +2836,900000000000000000000000000000000000000000000000000000000000002836.9999999999 +2837,900000000000000000000000000000000000000000000000000000000000002837.9999999999 +2838,900000000000000000000000000000000000000000000000000000000000002838.9999999999 +2839,900000000000000000000000000000000000000000000000000000000000002839.9999999999 +2840,900000000000000000000000000000000000000000000000000000000000002840.9999999999 +2841,900000000000000000000000000000000000000000000000000000000000002841.9999999999 +2842,900000000000000000000000000000000000000000000000000000000000002842.9999999999 +2843,900000000000000000000000000000000000000000000000000000000000002843.9999999999 +2844,900000000000000000000000000000000000000000000000000000000000002844.9999999999 +2845,900000000000000000000000000000000000000000000000000000000000002845.9999999999 +2846,900000000000000000000000000000000000000000000000000000000000002846.9999999999 +2847,900000000000000000000000000000000000000000000000000000000000002847.9999999999 +2848,900000000000000000000000000000000000000000000000000000000000002848.9999999999 +2849,900000000000000000000000000000000000000000000000000000000000002849.9999999999 +2850,900000000000000000000000000000000000000000000000000000000000002850.9999999999 +2851,900000000000000000000000000000000000000000000000000000000000002851.9999999999 +2852,900000000000000000000000000000000000000000000000000000000000002852.9999999999 +2853,900000000000000000000000000000000000000000000000000000000000002853.9999999999 +2854,900000000000000000000000000000000000000000000000000000000000002854.9999999999 +2855,900000000000000000000000000000000000000000000000000000000000002855.9999999999 +2856,900000000000000000000000000000000000000000000000000000000000002856.9999999999 +2857,900000000000000000000000000000000000000000000000000000000000002857.9999999999 +2858,900000000000000000000000000000000000000000000000000000000000002858.9999999999 +2859,900000000000000000000000000000000000000000000000000000000000002859.9999999999 +2860,900000000000000000000000000000000000000000000000000000000000002860.9999999999 +2861,900000000000000000000000000000000000000000000000000000000000002861.9999999999 +2862,900000000000000000000000000000000000000000000000000000000000002862.9999999999 +2863,900000000000000000000000000000000000000000000000000000000000002863.9999999999 +2864,900000000000000000000000000000000000000000000000000000000000002864.9999999999 +2865,900000000000000000000000000000000000000000000000000000000000002865.9999999999 +2866,900000000000000000000000000000000000000000000000000000000000002866.9999999999 +2867,900000000000000000000000000000000000000000000000000000000000002867.9999999999 +2868,900000000000000000000000000000000000000000000000000000000000002868.9999999999 +2869,900000000000000000000000000000000000000000000000000000000000002869.9999999999 +2870,900000000000000000000000000000000000000000000000000000000000002870.9999999999 +2871,900000000000000000000000000000000000000000000000000000000000002871.9999999999 +2872,900000000000000000000000000000000000000000000000000000000000002872.9999999999 +2873,900000000000000000000000000000000000000000000000000000000000002873.9999999999 +2874,900000000000000000000000000000000000000000000000000000000000002874.9999999999 +2875,900000000000000000000000000000000000000000000000000000000000002875.9999999999 +2876,900000000000000000000000000000000000000000000000000000000000002876.9999999999 +2877,900000000000000000000000000000000000000000000000000000000000002877.9999999999 +2878,900000000000000000000000000000000000000000000000000000000000002878.9999999999 +2879,900000000000000000000000000000000000000000000000000000000000002879.9999999999 +2880,900000000000000000000000000000000000000000000000000000000000002880.9999999999 +2881,900000000000000000000000000000000000000000000000000000000000002881.9999999999 +2882,900000000000000000000000000000000000000000000000000000000000002882.9999999999 +2883,900000000000000000000000000000000000000000000000000000000000002883.9999999999 +2884,900000000000000000000000000000000000000000000000000000000000002884.9999999999 +2885,900000000000000000000000000000000000000000000000000000000000002885.9999999999 +2886,900000000000000000000000000000000000000000000000000000000000002886.9999999999 +2887,900000000000000000000000000000000000000000000000000000000000002887.9999999999 +2888,900000000000000000000000000000000000000000000000000000000000002888.9999999999 +2889,900000000000000000000000000000000000000000000000000000000000002889.9999999999 +2890,900000000000000000000000000000000000000000000000000000000000002890.9999999999 +2891,900000000000000000000000000000000000000000000000000000000000002891.9999999999 +2892,900000000000000000000000000000000000000000000000000000000000002892.9999999999 +2893,900000000000000000000000000000000000000000000000000000000000002893.9999999999 +2894,900000000000000000000000000000000000000000000000000000000000002894.9999999999 +2895,900000000000000000000000000000000000000000000000000000000000002895.9999999999 +2896,900000000000000000000000000000000000000000000000000000000000002896.9999999999 +2897,900000000000000000000000000000000000000000000000000000000000002897.9999999999 +2898,900000000000000000000000000000000000000000000000000000000000002898.9999999999 +2899,900000000000000000000000000000000000000000000000000000000000002899.9999999999 +2900,900000000000000000000000000000000000000000000000000000000000002900.9999999999 +2901,900000000000000000000000000000000000000000000000000000000000002901.9999999999 +2902,900000000000000000000000000000000000000000000000000000000000002902.9999999999 +2903,900000000000000000000000000000000000000000000000000000000000002903.9999999999 +2904,900000000000000000000000000000000000000000000000000000000000002904.9999999999 +2905,900000000000000000000000000000000000000000000000000000000000002905.9999999999 +2906,900000000000000000000000000000000000000000000000000000000000002906.9999999999 +2907,900000000000000000000000000000000000000000000000000000000000002907.9999999999 +2908,900000000000000000000000000000000000000000000000000000000000002908.9999999999 +2909,900000000000000000000000000000000000000000000000000000000000002909.9999999999 +2910,900000000000000000000000000000000000000000000000000000000000002910.9999999999 +2911,900000000000000000000000000000000000000000000000000000000000002911.9999999999 +2912,900000000000000000000000000000000000000000000000000000000000002912.9999999999 +2913,900000000000000000000000000000000000000000000000000000000000002913.9999999999 +2914,900000000000000000000000000000000000000000000000000000000000002914.9999999999 +2915,900000000000000000000000000000000000000000000000000000000000002915.9999999999 +2916,900000000000000000000000000000000000000000000000000000000000002916.9999999999 +2917,900000000000000000000000000000000000000000000000000000000000002917.9999999999 +2918,900000000000000000000000000000000000000000000000000000000000002918.9999999999 +2919,900000000000000000000000000000000000000000000000000000000000002919.9999999999 +2920,900000000000000000000000000000000000000000000000000000000000002920.9999999999 +2921,900000000000000000000000000000000000000000000000000000000000002921.9999999999 +2922,900000000000000000000000000000000000000000000000000000000000002922.9999999999 +2923,900000000000000000000000000000000000000000000000000000000000002923.9999999999 +2924,900000000000000000000000000000000000000000000000000000000000002924.9999999999 +2925,900000000000000000000000000000000000000000000000000000000000002925.9999999999 +2926,900000000000000000000000000000000000000000000000000000000000002926.9999999999 +2927,900000000000000000000000000000000000000000000000000000000000002927.9999999999 +2928,900000000000000000000000000000000000000000000000000000000000002928.9999999999 +2929,900000000000000000000000000000000000000000000000000000000000002929.9999999999 +2930,900000000000000000000000000000000000000000000000000000000000002930.9999999999 +2931,900000000000000000000000000000000000000000000000000000000000002931.9999999999 +2932,900000000000000000000000000000000000000000000000000000000000002932.9999999999 +2933,900000000000000000000000000000000000000000000000000000000000002933.9999999999 +2934,900000000000000000000000000000000000000000000000000000000000002934.9999999999 +2935,900000000000000000000000000000000000000000000000000000000000002935.9999999999 +2936,900000000000000000000000000000000000000000000000000000000000002936.9999999999 +2937,900000000000000000000000000000000000000000000000000000000000002937.9999999999 +2938,900000000000000000000000000000000000000000000000000000000000002938.9999999999 +2939,900000000000000000000000000000000000000000000000000000000000002939.9999999999 +2940,900000000000000000000000000000000000000000000000000000000000002940.9999999999 +2941,900000000000000000000000000000000000000000000000000000000000002941.9999999999 +2942,900000000000000000000000000000000000000000000000000000000000002942.9999999999 +2943,900000000000000000000000000000000000000000000000000000000000002943.9999999999 +2944,900000000000000000000000000000000000000000000000000000000000002944.9999999999 +2945,900000000000000000000000000000000000000000000000000000000000002945.9999999999 +2946,900000000000000000000000000000000000000000000000000000000000002946.9999999999 +2947,900000000000000000000000000000000000000000000000000000000000002947.9999999999 +2948,900000000000000000000000000000000000000000000000000000000000002948.9999999999 +2949,900000000000000000000000000000000000000000000000000000000000002949.9999999999 +2950,900000000000000000000000000000000000000000000000000000000000002950.9999999999 +2951,900000000000000000000000000000000000000000000000000000000000002951.9999999999 +2952,900000000000000000000000000000000000000000000000000000000000002952.9999999999 +2953,900000000000000000000000000000000000000000000000000000000000002953.9999999999 +2954,900000000000000000000000000000000000000000000000000000000000002954.9999999999 +2955,900000000000000000000000000000000000000000000000000000000000002955.9999999999 +2956,900000000000000000000000000000000000000000000000000000000000002956.9999999999 +2957,900000000000000000000000000000000000000000000000000000000000002957.9999999999 +2958,900000000000000000000000000000000000000000000000000000000000002958.9999999999 +2959,900000000000000000000000000000000000000000000000000000000000002959.9999999999 +2960,900000000000000000000000000000000000000000000000000000000000002960.9999999999 +2961,900000000000000000000000000000000000000000000000000000000000002961.9999999999 +2962,900000000000000000000000000000000000000000000000000000000000002962.9999999999 +2963,900000000000000000000000000000000000000000000000000000000000002963.9999999999 +2964,900000000000000000000000000000000000000000000000000000000000002964.9999999999 +2965,900000000000000000000000000000000000000000000000000000000000002965.9999999999 +2966,900000000000000000000000000000000000000000000000000000000000002966.9999999999 +2967,900000000000000000000000000000000000000000000000000000000000002967.9999999999 +2968,900000000000000000000000000000000000000000000000000000000000002968.9999999999 +2969,900000000000000000000000000000000000000000000000000000000000002969.9999999999 +2970,900000000000000000000000000000000000000000000000000000000000002970.9999999999 +2971,900000000000000000000000000000000000000000000000000000000000002971.9999999999 +2972,900000000000000000000000000000000000000000000000000000000000002972.9999999999 +2973,900000000000000000000000000000000000000000000000000000000000002973.9999999999 +2974,900000000000000000000000000000000000000000000000000000000000002974.9999999999 +2975,900000000000000000000000000000000000000000000000000000000000002975.9999999999 +2976,900000000000000000000000000000000000000000000000000000000000002976.9999999999 +2977,900000000000000000000000000000000000000000000000000000000000002977.9999999999 +2978,900000000000000000000000000000000000000000000000000000000000002978.9999999999 +2979,900000000000000000000000000000000000000000000000000000000000002979.9999999999 +2980,900000000000000000000000000000000000000000000000000000000000002980.9999999999 +2981,900000000000000000000000000000000000000000000000000000000000002981.9999999999 +2982,900000000000000000000000000000000000000000000000000000000000002982.9999999999 +2983,900000000000000000000000000000000000000000000000000000000000002983.9999999999 +2984,900000000000000000000000000000000000000000000000000000000000002984.9999999999 +2985,900000000000000000000000000000000000000000000000000000000000002985.9999999999 +2986,900000000000000000000000000000000000000000000000000000000000002986.9999999999 +2987,900000000000000000000000000000000000000000000000000000000000002987.9999999999 +2988,900000000000000000000000000000000000000000000000000000000000002988.9999999999 +2989,900000000000000000000000000000000000000000000000000000000000002989.9999999999 +2990,900000000000000000000000000000000000000000000000000000000000002990.9999999999 +2991,900000000000000000000000000000000000000000000000000000000000002991.9999999999 +2992,900000000000000000000000000000000000000000000000000000000000002992.9999999999 +2993,900000000000000000000000000000000000000000000000000000000000002993.9999999999 +2994,900000000000000000000000000000000000000000000000000000000000002994.9999999999 +2995,900000000000000000000000000000000000000000000000000000000000002995.9999999999 +2996,900000000000000000000000000000000000000000000000000000000000002996.9999999999 +2997,900000000000000000000000000000000000000000000000000000000000002997.9999999999 +2998,900000000000000000000000000000000000000000000000000000000000002998.9999999999 +2999,900000000000000000000000000000000000000000000000000000000000002999.9999999999 +3000,900000000000000000000000000000000000000000000000000000000000003000.9999999999 +3001,900000000000000000000000000000000000000000000000000000000000003001.9999999999 +3002,900000000000000000000000000000000000000000000000000000000000003002.9999999999 +3003,900000000000000000000000000000000000000000000000000000000000003003.9999999999 +3004,900000000000000000000000000000000000000000000000000000000000003004.9999999999 +3005,900000000000000000000000000000000000000000000000000000000000003005.9999999999 +3006,900000000000000000000000000000000000000000000000000000000000003006.9999999999 +3007,900000000000000000000000000000000000000000000000000000000000003007.9999999999 +3008,900000000000000000000000000000000000000000000000000000000000003008.9999999999 +3009,900000000000000000000000000000000000000000000000000000000000003009.9999999999 +3010,900000000000000000000000000000000000000000000000000000000000003010.9999999999 +3011,900000000000000000000000000000000000000000000000000000000000003011.9999999999 +3012,900000000000000000000000000000000000000000000000000000000000003012.9999999999 +3013,900000000000000000000000000000000000000000000000000000000000003013.9999999999 +3014,900000000000000000000000000000000000000000000000000000000000003014.9999999999 +3015,900000000000000000000000000000000000000000000000000000000000003015.9999999999 +3016,900000000000000000000000000000000000000000000000000000000000003016.9999999999 +3017,900000000000000000000000000000000000000000000000000000000000003017.9999999999 +3018,900000000000000000000000000000000000000000000000000000000000003018.9999999999 +3019,900000000000000000000000000000000000000000000000000000000000003019.9999999999 +3020,900000000000000000000000000000000000000000000000000000000000003020.9999999999 +3021,900000000000000000000000000000000000000000000000000000000000003021.9999999999 +3022,900000000000000000000000000000000000000000000000000000000000003022.9999999999 +3023,900000000000000000000000000000000000000000000000000000000000003023.9999999999 +3024,900000000000000000000000000000000000000000000000000000000000003024.9999999999 +3025,900000000000000000000000000000000000000000000000000000000000003025.9999999999 +3026,900000000000000000000000000000000000000000000000000000000000003026.9999999999 +3027,900000000000000000000000000000000000000000000000000000000000003027.9999999999 +3028,900000000000000000000000000000000000000000000000000000000000003028.9999999999 +3029,900000000000000000000000000000000000000000000000000000000000003029.9999999999 +3030,900000000000000000000000000000000000000000000000000000000000003030.9999999999 +3031,900000000000000000000000000000000000000000000000000000000000003031.9999999999 +3032,900000000000000000000000000000000000000000000000000000000000003032.9999999999 +3033,900000000000000000000000000000000000000000000000000000000000003033.9999999999 +3034,900000000000000000000000000000000000000000000000000000000000003034.9999999999 +3035,900000000000000000000000000000000000000000000000000000000000003035.9999999999 +3036,900000000000000000000000000000000000000000000000000000000000003036.9999999999 +3037,900000000000000000000000000000000000000000000000000000000000003037.9999999999 +3038,900000000000000000000000000000000000000000000000000000000000003038.9999999999 +3039,900000000000000000000000000000000000000000000000000000000000003039.9999999999 +3040,900000000000000000000000000000000000000000000000000000000000003040.9999999999 +3041,900000000000000000000000000000000000000000000000000000000000003041.9999999999 +3042,900000000000000000000000000000000000000000000000000000000000003042.9999999999 +3043,900000000000000000000000000000000000000000000000000000000000003043.9999999999 +3044,900000000000000000000000000000000000000000000000000000000000003044.9999999999 +3045,900000000000000000000000000000000000000000000000000000000000003045.9999999999 +3046,900000000000000000000000000000000000000000000000000000000000003046.9999999999 +3047,900000000000000000000000000000000000000000000000000000000000003047.9999999999 +3048,900000000000000000000000000000000000000000000000000000000000003048.9999999999 +3049,900000000000000000000000000000000000000000000000000000000000003049.9999999999 +3050,900000000000000000000000000000000000000000000000000000000000003050.9999999999 +3051,900000000000000000000000000000000000000000000000000000000000003051.9999999999 +3052,900000000000000000000000000000000000000000000000000000000000003052.9999999999 +3053,900000000000000000000000000000000000000000000000000000000000003053.9999999999 +3054,900000000000000000000000000000000000000000000000000000000000003054.9999999999 +3055,900000000000000000000000000000000000000000000000000000000000003055.9999999999 +3056,900000000000000000000000000000000000000000000000000000000000003056.9999999999 +3057,900000000000000000000000000000000000000000000000000000000000003057.9999999999 +3058,900000000000000000000000000000000000000000000000000000000000003058.9999999999 +3059,900000000000000000000000000000000000000000000000000000000000003059.9999999999 +3060,900000000000000000000000000000000000000000000000000000000000003060.9999999999 +3061,900000000000000000000000000000000000000000000000000000000000003061.9999999999 +3062,900000000000000000000000000000000000000000000000000000000000003062.9999999999 +3063,900000000000000000000000000000000000000000000000000000000000003063.9999999999 +3064,900000000000000000000000000000000000000000000000000000000000003064.9999999999 +3065,900000000000000000000000000000000000000000000000000000000000003065.9999999999 +3066,900000000000000000000000000000000000000000000000000000000000003066.9999999999 +3067,900000000000000000000000000000000000000000000000000000000000003067.9999999999 +3068,900000000000000000000000000000000000000000000000000000000000003068.9999999999 +3069,900000000000000000000000000000000000000000000000000000000000003069.9999999999 +3070,900000000000000000000000000000000000000000000000000000000000003070.9999999999 +3071,900000000000000000000000000000000000000000000000000000000000003071.9999999999 +3072,900000000000000000000000000000000000000000000000000000000000003072.9999999999 +3073,900000000000000000000000000000000000000000000000000000000000003073.9999999999 +3074,900000000000000000000000000000000000000000000000000000000000003074.9999999999 +3075,900000000000000000000000000000000000000000000000000000000000003075.9999999999 +3076,900000000000000000000000000000000000000000000000000000000000003076.9999999999 +3077,900000000000000000000000000000000000000000000000000000000000003077.9999999999 +3078,900000000000000000000000000000000000000000000000000000000000003078.9999999999 +3079,900000000000000000000000000000000000000000000000000000000000003079.9999999999 +3080,900000000000000000000000000000000000000000000000000000000000003080.9999999999 +3081,900000000000000000000000000000000000000000000000000000000000003081.9999999999 +3082,900000000000000000000000000000000000000000000000000000000000003082.9999999999 +3083,900000000000000000000000000000000000000000000000000000000000003083.9999999999 +3084,900000000000000000000000000000000000000000000000000000000000003084.9999999999 +3085,900000000000000000000000000000000000000000000000000000000000003085.9999999999 +3086,900000000000000000000000000000000000000000000000000000000000003086.9999999999 +3087,900000000000000000000000000000000000000000000000000000000000003087.9999999999 +3088,900000000000000000000000000000000000000000000000000000000000003088.9999999999 +3089,900000000000000000000000000000000000000000000000000000000000003089.9999999999 +3090,900000000000000000000000000000000000000000000000000000000000003090.9999999999 +3091,900000000000000000000000000000000000000000000000000000000000003091.9999999999 +3092,900000000000000000000000000000000000000000000000000000000000003092.9999999999 +3093,900000000000000000000000000000000000000000000000000000000000003093.9999999999 +3094,900000000000000000000000000000000000000000000000000000000000003094.9999999999 +3095,900000000000000000000000000000000000000000000000000000000000003095.9999999999 +3096,900000000000000000000000000000000000000000000000000000000000003096.9999999999 +3097,900000000000000000000000000000000000000000000000000000000000003097.9999999999 +3098,900000000000000000000000000000000000000000000000000000000000003098.9999999999 +3099,900000000000000000000000000000000000000000000000000000000000003099.9999999999 +3100,900000000000000000000000000000000000000000000000000000000000003100.9999999999 +3101,900000000000000000000000000000000000000000000000000000000000003101.9999999999 +3102,900000000000000000000000000000000000000000000000000000000000003102.9999999999 +3103,900000000000000000000000000000000000000000000000000000000000003103.9999999999 +3104,900000000000000000000000000000000000000000000000000000000000003104.9999999999 +3105,900000000000000000000000000000000000000000000000000000000000003105.9999999999 +3106,900000000000000000000000000000000000000000000000000000000000003106.9999999999 +3107,900000000000000000000000000000000000000000000000000000000000003107.9999999999 +3108,900000000000000000000000000000000000000000000000000000000000003108.9999999999 +3109,900000000000000000000000000000000000000000000000000000000000003109.9999999999 +3110,900000000000000000000000000000000000000000000000000000000000003110.9999999999 +3111,900000000000000000000000000000000000000000000000000000000000003111.9999999999 +3112,900000000000000000000000000000000000000000000000000000000000003112.9999999999 +3113,900000000000000000000000000000000000000000000000000000000000003113.9999999999 +3114,900000000000000000000000000000000000000000000000000000000000003114.9999999999 +3115,900000000000000000000000000000000000000000000000000000000000003115.9999999999 +3116,900000000000000000000000000000000000000000000000000000000000003116.9999999999 +3117,900000000000000000000000000000000000000000000000000000000000003117.9999999999 +3118,900000000000000000000000000000000000000000000000000000000000003118.9999999999 +3119,900000000000000000000000000000000000000000000000000000000000003119.9999999999 +3120,900000000000000000000000000000000000000000000000000000000000003120.9999999999 +3121,900000000000000000000000000000000000000000000000000000000000003121.9999999999 +3122,900000000000000000000000000000000000000000000000000000000000003122.9999999999 +3123,900000000000000000000000000000000000000000000000000000000000003123.9999999999 +3124,900000000000000000000000000000000000000000000000000000000000003124.9999999999 +3125,900000000000000000000000000000000000000000000000000000000000003125.9999999999 +3126,900000000000000000000000000000000000000000000000000000000000003126.9999999999 +3127,900000000000000000000000000000000000000000000000000000000000003127.9999999999 +3128,900000000000000000000000000000000000000000000000000000000000003128.9999999999 +3129,900000000000000000000000000000000000000000000000000000000000003129.9999999999 +3130,900000000000000000000000000000000000000000000000000000000000003130.9999999999 +3131,900000000000000000000000000000000000000000000000000000000000003131.9999999999 +3132,900000000000000000000000000000000000000000000000000000000000003132.9999999999 +3133,900000000000000000000000000000000000000000000000000000000000003133.9999999999 +3134,900000000000000000000000000000000000000000000000000000000000003134.9999999999 +3135,900000000000000000000000000000000000000000000000000000000000003135.9999999999 +3136,900000000000000000000000000000000000000000000000000000000000003136.9999999999 +3137,900000000000000000000000000000000000000000000000000000000000003137.9999999999 +3138,900000000000000000000000000000000000000000000000000000000000003138.9999999999 +3139,900000000000000000000000000000000000000000000000000000000000003139.9999999999 +3140,900000000000000000000000000000000000000000000000000000000000003140.9999999999 +3141,900000000000000000000000000000000000000000000000000000000000003141.9999999999 +3142,900000000000000000000000000000000000000000000000000000000000003142.9999999999 +3143,900000000000000000000000000000000000000000000000000000000000003143.9999999999 +3144,900000000000000000000000000000000000000000000000000000000000003144.9999999999 +3145,900000000000000000000000000000000000000000000000000000000000003145.9999999999 +3146,900000000000000000000000000000000000000000000000000000000000003146.9999999999 +3147,900000000000000000000000000000000000000000000000000000000000003147.9999999999 +3148,900000000000000000000000000000000000000000000000000000000000003148.9999999999 +3149,900000000000000000000000000000000000000000000000000000000000003149.9999999999 +3150,900000000000000000000000000000000000000000000000000000000000003150.9999999999 +3151,900000000000000000000000000000000000000000000000000000000000003151.9999999999 +3152,900000000000000000000000000000000000000000000000000000000000003152.9999999999 +3153,900000000000000000000000000000000000000000000000000000000000003153.9999999999 +3154,900000000000000000000000000000000000000000000000000000000000003154.9999999999 +3155,900000000000000000000000000000000000000000000000000000000000003155.9999999999 +3156,900000000000000000000000000000000000000000000000000000000000003156.9999999999 +3157,900000000000000000000000000000000000000000000000000000000000003157.9999999999 +3158,900000000000000000000000000000000000000000000000000000000000003158.9999999999 +3159,900000000000000000000000000000000000000000000000000000000000003159.9999999999 +3160,900000000000000000000000000000000000000000000000000000000000003160.9999999999 +3161,900000000000000000000000000000000000000000000000000000000000003161.9999999999 +3162,900000000000000000000000000000000000000000000000000000000000003162.9999999999 +3163,900000000000000000000000000000000000000000000000000000000000003163.9999999999 +3164,900000000000000000000000000000000000000000000000000000000000003164.9999999999 +3165,900000000000000000000000000000000000000000000000000000000000003165.9999999999 +3166,900000000000000000000000000000000000000000000000000000000000003166.9999999999 +3167,900000000000000000000000000000000000000000000000000000000000003167.9999999999 +3168,900000000000000000000000000000000000000000000000000000000000003168.9999999999 +3169,900000000000000000000000000000000000000000000000000000000000003169.9999999999 +3170,900000000000000000000000000000000000000000000000000000000000003170.9999999999 +3171,900000000000000000000000000000000000000000000000000000000000003171.9999999999 +3172,900000000000000000000000000000000000000000000000000000000000003172.9999999999 +3173,900000000000000000000000000000000000000000000000000000000000003173.9999999999 +3174,900000000000000000000000000000000000000000000000000000000000003174.9999999999 +3175,900000000000000000000000000000000000000000000000000000000000003175.9999999999 +3176,900000000000000000000000000000000000000000000000000000000000003176.9999999999 +3177,900000000000000000000000000000000000000000000000000000000000003177.9999999999 +3178,900000000000000000000000000000000000000000000000000000000000003178.9999999999 +3179,900000000000000000000000000000000000000000000000000000000000003179.9999999999 +3180,900000000000000000000000000000000000000000000000000000000000003180.9999999999 +3181,900000000000000000000000000000000000000000000000000000000000003181.9999999999 +3182,900000000000000000000000000000000000000000000000000000000000003182.9999999999 +3183,900000000000000000000000000000000000000000000000000000000000003183.9999999999 +3184,900000000000000000000000000000000000000000000000000000000000003184.9999999999 +3185,900000000000000000000000000000000000000000000000000000000000003185.9999999999 +3186,900000000000000000000000000000000000000000000000000000000000003186.9999999999 +3187,900000000000000000000000000000000000000000000000000000000000003187.9999999999 +3188,900000000000000000000000000000000000000000000000000000000000003188.9999999999 +3189,900000000000000000000000000000000000000000000000000000000000003189.9999999999 +3190,900000000000000000000000000000000000000000000000000000000000003190.9999999999 +3191,900000000000000000000000000000000000000000000000000000000000003191.9999999999 +3192,900000000000000000000000000000000000000000000000000000000000003192.9999999999 +3193,900000000000000000000000000000000000000000000000000000000000003193.9999999999 +3194,900000000000000000000000000000000000000000000000000000000000003194.9999999999 +3195,900000000000000000000000000000000000000000000000000000000000003195.9999999999 +3196,900000000000000000000000000000000000000000000000000000000000003196.9999999999 +3197,900000000000000000000000000000000000000000000000000000000000003197.9999999999 +3198,900000000000000000000000000000000000000000000000000000000000003198.9999999999 +3199,900000000000000000000000000000000000000000000000000000000000003199.9999999999 +3200,900000000000000000000000000000000000000000000000000000000000003200.9999999999 +3201,900000000000000000000000000000000000000000000000000000000000003201.9999999999 +3202,900000000000000000000000000000000000000000000000000000000000003202.9999999999 +3203,900000000000000000000000000000000000000000000000000000000000003203.9999999999 +3204,900000000000000000000000000000000000000000000000000000000000003204.9999999999 +3205,900000000000000000000000000000000000000000000000000000000000003205.9999999999 +3206,900000000000000000000000000000000000000000000000000000000000003206.9999999999 +3207,900000000000000000000000000000000000000000000000000000000000003207.9999999999 +3208,900000000000000000000000000000000000000000000000000000000000003208.9999999999 +3209,900000000000000000000000000000000000000000000000000000000000003209.9999999999 +3210,900000000000000000000000000000000000000000000000000000000000003210.9999999999 +3211,900000000000000000000000000000000000000000000000000000000000003211.9999999999 +3212,900000000000000000000000000000000000000000000000000000000000003212.9999999999 +3213,900000000000000000000000000000000000000000000000000000000000003213.9999999999 +3214,900000000000000000000000000000000000000000000000000000000000003214.9999999999 +3215,900000000000000000000000000000000000000000000000000000000000003215.9999999999 +3216,900000000000000000000000000000000000000000000000000000000000003216.9999999999 +3217,900000000000000000000000000000000000000000000000000000000000003217.9999999999 +3218,900000000000000000000000000000000000000000000000000000000000003218.9999999999 +3219,900000000000000000000000000000000000000000000000000000000000003219.9999999999 +3220,900000000000000000000000000000000000000000000000000000000000003220.9999999999 +3221,900000000000000000000000000000000000000000000000000000000000003221.9999999999 +3222,900000000000000000000000000000000000000000000000000000000000003222.9999999999 +3223,900000000000000000000000000000000000000000000000000000000000003223.9999999999 +3224,900000000000000000000000000000000000000000000000000000000000003224.9999999999 +3225,900000000000000000000000000000000000000000000000000000000000003225.9999999999 +3226,900000000000000000000000000000000000000000000000000000000000003226.9999999999 +3227,900000000000000000000000000000000000000000000000000000000000003227.9999999999 +3228,900000000000000000000000000000000000000000000000000000000000003228.9999999999 +3229,900000000000000000000000000000000000000000000000000000000000003229.9999999999 +3230,900000000000000000000000000000000000000000000000000000000000003230.9999999999 +3231,900000000000000000000000000000000000000000000000000000000000003231.9999999999 +3232,900000000000000000000000000000000000000000000000000000000000003232.9999999999 +3233,900000000000000000000000000000000000000000000000000000000000003233.9999999999 +3234,900000000000000000000000000000000000000000000000000000000000003234.9999999999 +3235,900000000000000000000000000000000000000000000000000000000000003235.9999999999 +3236,900000000000000000000000000000000000000000000000000000000000003236.9999999999 +3237,900000000000000000000000000000000000000000000000000000000000003237.9999999999 +3238,900000000000000000000000000000000000000000000000000000000000003238.9999999999 +3239,900000000000000000000000000000000000000000000000000000000000003239.9999999999 +3240,900000000000000000000000000000000000000000000000000000000000003240.9999999999 +3241,900000000000000000000000000000000000000000000000000000000000003241.9999999999 +3242,900000000000000000000000000000000000000000000000000000000000003242.9999999999 +3243,900000000000000000000000000000000000000000000000000000000000003243.9999999999 +3244,900000000000000000000000000000000000000000000000000000000000003244.9999999999 +3245,900000000000000000000000000000000000000000000000000000000000003245.9999999999 +3246,900000000000000000000000000000000000000000000000000000000000003246.9999999999 +3247,900000000000000000000000000000000000000000000000000000000000003247.9999999999 +3248,900000000000000000000000000000000000000000000000000000000000003248.9999999999 +3249,900000000000000000000000000000000000000000000000000000000000003249.9999999999 +3250,900000000000000000000000000000000000000000000000000000000000003250.9999999999 +3251,900000000000000000000000000000000000000000000000000000000000003251.9999999999 +3252,900000000000000000000000000000000000000000000000000000000000003252.9999999999 +3253,900000000000000000000000000000000000000000000000000000000000003253.9999999999 +3254,900000000000000000000000000000000000000000000000000000000000003254.9999999999 +3255,900000000000000000000000000000000000000000000000000000000000003255.9999999999 +3256,900000000000000000000000000000000000000000000000000000000000003256.9999999999 +3257,900000000000000000000000000000000000000000000000000000000000003257.9999999999 +3258,900000000000000000000000000000000000000000000000000000000000003258.9999999999 +3259,900000000000000000000000000000000000000000000000000000000000003259.9999999999 +3260,900000000000000000000000000000000000000000000000000000000000003260.9999999999 +3261,900000000000000000000000000000000000000000000000000000000000003261.9999999999 +3262,900000000000000000000000000000000000000000000000000000000000003262.9999999999 +3263,900000000000000000000000000000000000000000000000000000000000003263.9999999999 +3264,900000000000000000000000000000000000000000000000000000000000003264.9999999999 +3265,900000000000000000000000000000000000000000000000000000000000003265.9999999999 +3266,900000000000000000000000000000000000000000000000000000000000003266.9999999999 +3267,900000000000000000000000000000000000000000000000000000000000003267.9999999999 +3268,900000000000000000000000000000000000000000000000000000000000003268.9999999999 +3269,900000000000000000000000000000000000000000000000000000000000003269.9999999999 +3270,900000000000000000000000000000000000000000000000000000000000003270.9999999999 +3271,900000000000000000000000000000000000000000000000000000000000003271.9999999999 +3272,900000000000000000000000000000000000000000000000000000000000003272.9999999999 +3273,900000000000000000000000000000000000000000000000000000000000003273.9999999999 +3274,900000000000000000000000000000000000000000000000000000000000003274.9999999999 +3275,900000000000000000000000000000000000000000000000000000000000003275.9999999999 +3276,900000000000000000000000000000000000000000000000000000000000003276.9999999999 +3277,900000000000000000000000000000000000000000000000000000000000003277.9999999999 +3278,900000000000000000000000000000000000000000000000000000000000003278.9999999999 +3279,900000000000000000000000000000000000000000000000000000000000003279.9999999999 +3280,900000000000000000000000000000000000000000000000000000000000003280.9999999999 +3281,900000000000000000000000000000000000000000000000000000000000003281.9999999999 +3282,900000000000000000000000000000000000000000000000000000000000003282.9999999999 +3283,900000000000000000000000000000000000000000000000000000000000003283.9999999999 +3284,900000000000000000000000000000000000000000000000000000000000003284.9999999999 +3285,900000000000000000000000000000000000000000000000000000000000003285.9999999999 +3286,900000000000000000000000000000000000000000000000000000000000003286.9999999999 +3287,900000000000000000000000000000000000000000000000000000000000003287.9999999999 +3288,900000000000000000000000000000000000000000000000000000000000003288.9999999999 +3289,900000000000000000000000000000000000000000000000000000000000003289.9999999999 +3290,900000000000000000000000000000000000000000000000000000000000003290.9999999999 +3291,900000000000000000000000000000000000000000000000000000000000003291.9999999999 +3292,900000000000000000000000000000000000000000000000000000000000003292.9999999999 +3293,900000000000000000000000000000000000000000000000000000000000003293.9999999999 +3294,900000000000000000000000000000000000000000000000000000000000003294.9999999999 +3295,900000000000000000000000000000000000000000000000000000000000003295.9999999999 +3296,900000000000000000000000000000000000000000000000000000000000003296.9999999999 +3297,900000000000000000000000000000000000000000000000000000000000003297.9999999999 +3298,900000000000000000000000000000000000000000000000000000000000003298.9999999999 +3299,900000000000000000000000000000000000000000000000000000000000003299.9999999999 +3300,900000000000000000000000000000000000000000000000000000000000003300.9999999999 +3301,900000000000000000000000000000000000000000000000000000000000003301.9999999999 +3302,900000000000000000000000000000000000000000000000000000000000003302.9999999999 +3303,900000000000000000000000000000000000000000000000000000000000003303.9999999999 +3304,900000000000000000000000000000000000000000000000000000000000003304.9999999999 +3305,900000000000000000000000000000000000000000000000000000000000003305.9999999999 +3306,900000000000000000000000000000000000000000000000000000000000003306.9999999999 +3307,900000000000000000000000000000000000000000000000000000000000003307.9999999999 +3308,900000000000000000000000000000000000000000000000000000000000003308.9999999999 +3309,900000000000000000000000000000000000000000000000000000000000003309.9999999999 +3310,900000000000000000000000000000000000000000000000000000000000003310.9999999999 +3311,900000000000000000000000000000000000000000000000000000000000003311.9999999999 +3312,900000000000000000000000000000000000000000000000000000000000003312.9999999999 +3313,900000000000000000000000000000000000000000000000000000000000003313.9999999999 +3314,900000000000000000000000000000000000000000000000000000000000003314.9999999999 +3315,900000000000000000000000000000000000000000000000000000000000003315.9999999999 +3316,900000000000000000000000000000000000000000000000000000000000003316.9999999999 +3317,900000000000000000000000000000000000000000000000000000000000003317.9999999999 +3318,900000000000000000000000000000000000000000000000000000000000003318.9999999999 +3319,900000000000000000000000000000000000000000000000000000000000003319.9999999999 +3320,900000000000000000000000000000000000000000000000000000000000003320.9999999999 +3321,900000000000000000000000000000000000000000000000000000000000003321.9999999999 +3322,900000000000000000000000000000000000000000000000000000000000003322.9999999999 +3323,900000000000000000000000000000000000000000000000000000000000003323.9999999999 +3324,900000000000000000000000000000000000000000000000000000000000003324.9999999999 +3325,900000000000000000000000000000000000000000000000000000000000003325.9999999999 +3326,900000000000000000000000000000000000000000000000000000000000003326.9999999999 +3327,900000000000000000000000000000000000000000000000000000000000003327.9999999999 +3328,900000000000000000000000000000000000000000000000000000000000003328.9999999999 +3329,900000000000000000000000000000000000000000000000000000000000003329.9999999999 +3330,900000000000000000000000000000000000000000000000000000000000003330.9999999999 +3331,900000000000000000000000000000000000000000000000000000000000003331.9999999999 +3332,900000000000000000000000000000000000000000000000000000000000003332.9999999999 +3333,900000000000000000000000000000000000000000000000000000000000003333.9999999999 +3334,900000000000000000000000000000000000000000000000000000000000003334.9999999999 +3335,900000000000000000000000000000000000000000000000000000000000003335.9999999999 +3336,900000000000000000000000000000000000000000000000000000000000003336.9999999999 +3337,900000000000000000000000000000000000000000000000000000000000003337.9999999999 +3338,900000000000000000000000000000000000000000000000000000000000003338.9999999999 +3339,900000000000000000000000000000000000000000000000000000000000003339.9999999999 +3340,900000000000000000000000000000000000000000000000000000000000003340.9999999999 +3341,900000000000000000000000000000000000000000000000000000000000003341.9999999999 +3342,900000000000000000000000000000000000000000000000000000000000003342.9999999999 +3343,900000000000000000000000000000000000000000000000000000000000003343.9999999999 +3344,900000000000000000000000000000000000000000000000000000000000003344.9999999999 +3345,900000000000000000000000000000000000000000000000000000000000003345.9999999999 +3346,900000000000000000000000000000000000000000000000000000000000003346.9999999999 +3347,900000000000000000000000000000000000000000000000000000000000003347.9999999999 +3348,900000000000000000000000000000000000000000000000000000000000003348.9999999999 +3349,900000000000000000000000000000000000000000000000000000000000003349.9999999999 +3350,900000000000000000000000000000000000000000000000000000000000003350.9999999999 +3351,900000000000000000000000000000000000000000000000000000000000003351.9999999999 +3352,900000000000000000000000000000000000000000000000000000000000003352.9999999999 +3353,900000000000000000000000000000000000000000000000000000000000003353.9999999999 +3354,900000000000000000000000000000000000000000000000000000000000003354.9999999999 +3355,900000000000000000000000000000000000000000000000000000000000003355.9999999999 +3356,900000000000000000000000000000000000000000000000000000000000003356.9999999999 +3357,900000000000000000000000000000000000000000000000000000000000003357.9999999999 +3358,900000000000000000000000000000000000000000000000000000000000003358.9999999999 +3359,900000000000000000000000000000000000000000000000000000000000003359.9999999999 +3360,900000000000000000000000000000000000000000000000000000000000003360.9999999999 +3361,900000000000000000000000000000000000000000000000000000000000003361.9999999999 +3362,900000000000000000000000000000000000000000000000000000000000003362.9999999999 +3363,900000000000000000000000000000000000000000000000000000000000003363.9999999999 +3364,900000000000000000000000000000000000000000000000000000000000003364.9999999999 +3365,900000000000000000000000000000000000000000000000000000000000003365.9999999999 +3366,900000000000000000000000000000000000000000000000000000000000003366.9999999999 +3367,900000000000000000000000000000000000000000000000000000000000003367.9999999999 +3368,900000000000000000000000000000000000000000000000000000000000003368.9999999999 +3369,900000000000000000000000000000000000000000000000000000000000003369.9999999999 +3370,900000000000000000000000000000000000000000000000000000000000003370.9999999999 +3371,900000000000000000000000000000000000000000000000000000000000003371.9999999999 +3372,900000000000000000000000000000000000000000000000000000000000003372.9999999999 +3373,900000000000000000000000000000000000000000000000000000000000003373.9999999999 +3374,900000000000000000000000000000000000000000000000000000000000003374.9999999999 +3375,900000000000000000000000000000000000000000000000000000000000003375.9999999999 +3376,900000000000000000000000000000000000000000000000000000000000003376.9999999999 +3377,900000000000000000000000000000000000000000000000000000000000003377.9999999999 +3378,900000000000000000000000000000000000000000000000000000000000003378.9999999999 +3379,900000000000000000000000000000000000000000000000000000000000003379.9999999999 +3380,900000000000000000000000000000000000000000000000000000000000003380.9999999999 +3381,900000000000000000000000000000000000000000000000000000000000003381.9999999999 +3382,900000000000000000000000000000000000000000000000000000000000003382.9999999999 +3383,900000000000000000000000000000000000000000000000000000000000003383.9999999999 +3384,900000000000000000000000000000000000000000000000000000000000003384.9999999999 +3385,900000000000000000000000000000000000000000000000000000000000003385.9999999999 +3386,900000000000000000000000000000000000000000000000000000000000003386.9999999999 +3387,900000000000000000000000000000000000000000000000000000000000003387.9999999999 +3388,900000000000000000000000000000000000000000000000000000000000003388.9999999999 +3389,900000000000000000000000000000000000000000000000000000000000003389.9999999999 +3390,900000000000000000000000000000000000000000000000000000000000003390.9999999999 +3391,900000000000000000000000000000000000000000000000000000000000003391.9999999999 +3392,900000000000000000000000000000000000000000000000000000000000003392.9999999999 +3393,900000000000000000000000000000000000000000000000000000000000003393.9999999999 +3394,900000000000000000000000000000000000000000000000000000000000003394.9999999999 +3395,900000000000000000000000000000000000000000000000000000000000003395.9999999999 +3396,900000000000000000000000000000000000000000000000000000000000003396.9999999999 +3397,900000000000000000000000000000000000000000000000000000000000003397.9999999999 +3398,900000000000000000000000000000000000000000000000000000000000003398.9999999999 +3399,900000000000000000000000000000000000000000000000000000000000003399.9999999999 +3400,900000000000000000000000000000000000000000000000000000000000003400.9999999999 +3401,900000000000000000000000000000000000000000000000000000000000003401.9999999999 +3402,900000000000000000000000000000000000000000000000000000000000003402.9999999999 +3403,900000000000000000000000000000000000000000000000000000000000003403.9999999999 +3404,900000000000000000000000000000000000000000000000000000000000003404.9999999999 +3405,900000000000000000000000000000000000000000000000000000000000003405.9999999999 +3406,900000000000000000000000000000000000000000000000000000000000003406.9999999999 +3407,900000000000000000000000000000000000000000000000000000000000003407.9999999999 +3408,900000000000000000000000000000000000000000000000000000000000003408.9999999999 +3409,900000000000000000000000000000000000000000000000000000000000003409.9999999999 +3410,900000000000000000000000000000000000000000000000000000000000003410.9999999999 +3411,900000000000000000000000000000000000000000000000000000000000003411.9999999999 +3412,900000000000000000000000000000000000000000000000000000000000003412.9999999999 +3413,900000000000000000000000000000000000000000000000000000000000003413.9999999999 +3414,900000000000000000000000000000000000000000000000000000000000003414.9999999999 +3415,900000000000000000000000000000000000000000000000000000000000003415.9999999999 +3416,900000000000000000000000000000000000000000000000000000000000003416.9999999999 +3417,900000000000000000000000000000000000000000000000000000000000003417.9999999999 +3418,900000000000000000000000000000000000000000000000000000000000003418.9999999999 +3419,900000000000000000000000000000000000000000000000000000000000003419.9999999999 +3420,900000000000000000000000000000000000000000000000000000000000003420.9999999999 +3421,900000000000000000000000000000000000000000000000000000000000003421.9999999999 +3422,900000000000000000000000000000000000000000000000000000000000003422.9999999999 +3423,900000000000000000000000000000000000000000000000000000000000003423.9999999999 +3424,900000000000000000000000000000000000000000000000000000000000003424.9999999999 +3425,900000000000000000000000000000000000000000000000000000000000003425.9999999999 +3426,900000000000000000000000000000000000000000000000000000000000003426.9999999999 +3427,900000000000000000000000000000000000000000000000000000000000003427.9999999999 +3428,900000000000000000000000000000000000000000000000000000000000003428.9999999999 +3429,900000000000000000000000000000000000000000000000000000000000003429.9999999999 +3430,900000000000000000000000000000000000000000000000000000000000003430.9999999999 +3431,900000000000000000000000000000000000000000000000000000000000003431.9999999999 +3432,900000000000000000000000000000000000000000000000000000000000003432.9999999999 +3433,900000000000000000000000000000000000000000000000000000000000003433.9999999999 +3434,900000000000000000000000000000000000000000000000000000000000003434.9999999999 +3435,900000000000000000000000000000000000000000000000000000000000003435.9999999999 +3436,900000000000000000000000000000000000000000000000000000000000003436.9999999999 +3437,900000000000000000000000000000000000000000000000000000000000003437.9999999999 +3438,900000000000000000000000000000000000000000000000000000000000003438.9999999999 +3439,900000000000000000000000000000000000000000000000000000000000003439.9999999999 +3440,900000000000000000000000000000000000000000000000000000000000003440.9999999999 +3441,900000000000000000000000000000000000000000000000000000000000003441.9999999999 +3442,900000000000000000000000000000000000000000000000000000000000003442.9999999999 +3443,900000000000000000000000000000000000000000000000000000000000003443.9999999999 +3444,900000000000000000000000000000000000000000000000000000000000003444.9999999999 +3445,900000000000000000000000000000000000000000000000000000000000003445.9999999999 +3446,900000000000000000000000000000000000000000000000000000000000003446.9999999999 +3447,900000000000000000000000000000000000000000000000000000000000003447.9999999999 +3448,900000000000000000000000000000000000000000000000000000000000003448.9999999999 +3449,900000000000000000000000000000000000000000000000000000000000003449.9999999999 +3450,900000000000000000000000000000000000000000000000000000000000003450.9999999999 +3451,900000000000000000000000000000000000000000000000000000000000003451.9999999999 +3452,900000000000000000000000000000000000000000000000000000000000003452.9999999999 +3453,900000000000000000000000000000000000000000000000000000000000003453.9999999999 +3454,900000000000000000000000000000000000000000000000000000000000003454.9999999999 +3455,900000000000000000000000000000000000000000000000000000000000003455.9999999999 +3456,900000000000000000000000000000000000000000000000000000000000003456.9999999999 +3457,900000000000000000000000000000000000000000000000000000000000003457.9999999999 +3458,900000000000000000000000000000000000000000000000000000000000003458.9999999999 +3459,900000000000000000000000000000000000000000000000000000000000003459.9999999999 +3460,900000000000000000000000000000000000000000000000000000000000003460.9999999999 +3461,900000000000000000000000000000000000000000000000000000000000003461.9999999999 +3462,900000000000000000000000000000000000000000000000000000000000003462.9999999999 +3463,900000000000000000000000000000000000000000000000000000000000003463.9999999999 +3464,900000000000000000000000000000000000000000000000000000000000003464.9999999999 +3465,900000000000000000000000000000000000000000000000000000000000003465.9999999999 +3466,900000000000000000000000000000000000000000000000000000000000003466.9999999999 +3467,900000000000000000000000000000000000000000000000000000000000003467.9999999999 +3468,900000000000000000000000000000000000000000000000000000000000003468.9999999999 +3469,900000000000000000000000000000000000000000000000000000000000003469.9999999999 +3470,900000000000000000000000000000000000000000000000000000000000003470.9999999999 +3471,900000000000000000000000000000000000000000000000000000000000003471.9999999999 +3472,900000000000000000000000000000000000000000000000000000000000003472.9999999999 +3473,900000000000000000000000000000000000000000000000000000000000003473.9999999999 +3474,900000000000000000000000000000000000000000000000000000000000003474.9999999999 +3475,900000000000000000000000000000000000000000000000000000000000003475.9999999999 +3476,900000000000000000000000000000000000000000000000000000000000003476.9999999999 +3477,900000000000000000000000000000000000000000000000000000000000003477.9999999999 +3478,900000000000000000000000000000000000000000000000000000000000003478.9999999999 +3479,900000000000000000000000000000000000000000000000000000000000003479.9999999999 +3480,900000000000000000000000000000000000000000000000000000000000003480.9999999999 +3481,900000000000000000000000000000000000000000000000000000000000003481.9999999999 +3482,900000000000000000000000000000000000000000000000000000000000003482.9999999999 +3483,900000000000000000000000000000000000000000000000000000000000003483.9999999999 +3484,900000000000000000000000000000000000000000000000000000000000003484.9999999999 +3485,900000000000000000000000000000000000000000000000000000000000003485.9999999999 +3486,900000000000000000000000000000000000000000000000000000000000003486.9999999999 +3487,900000000000000000000000000000000000000000000000000000000000003487.9999999999 +3488,900000000000000000000000000000000000000000000000000000000000003488.9999999999 +3489,900000000000000000000000000000000000000000000000000000000000003489.9999999999 +3490,900000000000000000000000000000000000000000000000000000000000003490.9999999999 +3491,900000000000000000000000000000000000000000000000000000000000003491.9999999999 +3492,900000000000000000000000000000000000000000000000000000000000003492.9999999999 +3493,900000000000000000000000000000000000000000000000000000000000003493.9999999999 +3494,900000000000000000000000000000000000000000000000000000000000003494.9999999999 +3495,900000000000000000000000000000000000000000000000000000000000003495.9999999999 +3496,900000000000000000000000000000000000000000000000000000000000003496.9999999999 +3497,900000000000000000000000000000000000000000000000000000000000003497.9999999999 +3498,900000000000000000000000000000000000000000000000000000000000003498.9999999999 +3499,900000000000000000000000000000000000000000000000000000000000003499.9999999999 +3500,900000000000000000000000000000000000000000000000000000000000003500.9999999999 +3501,900000000000000000000000000000000000000000000000000000000000003501.9999999999 +3502,900000000000000000000000000000000000000000000000000000000000003502.9999999999 +3503,900000000000000000000000000000000000000000000000000000000000003503.9999999999 +3504,900000000000000000000000000000000000000000000000000000000000003504.9999999999 +3505,900000000000000000000000000000000000000000000000000000000000003505.9999999999 +3506,900000000000000000000000000000000000000000000000000000000000003506.9999999999 +3507,900000000000000000000000000000000000000000000000000000000000003507.9999999999 +3508,900000000000000000000000000000000000000000000000000000000000003508.9999999999 +3509,900000000000000000000000000000000000000000000000000000000000003509.9999999999 +3510,900000000000000000000000000000000000000000000000000000000000003510.9999999999 +3511,900000000000000000000000000000000000000000000000000000000000003511.9999999999 +3512,900000000000000000000000000000000000000000000000000000000000003512.9999999999 +3513,900000000000000000000000000000000000000000000000000000000000003513.9999999999 +3514,900000000000000000000000000000000000000000000000000000000000003514.9999999999 +3515,900000000000000000000000000000000000000000000000000000000000003515.9999999999 +3516,900000000000000000000000000000000000000000000000000000000000003516.9999999999 +3517,900000000000000000000000000000000000000000000000000000000000003517.9999999999 +3518,900000000000000000000000000000000000000000000000000000000000003518.9999999999 +3519,900000000000000000000000000000000000000000000000000000000000003519.9999999999 +3520,900000000000000000000000000000000000000000000000000000000000003520.9999999999 +3521,900000000000000000000000000000000000000000000000000000000000003521.9999999999 +3522,900000000000000000000000000000000000000000000000000000000000003522.9999999999 +3523,900000000000000000000000000000000000000000000000000000000000003523.9999999999 +3524,900000000000000000000000000000000000000000000000000000000000003524.9999999999 +3525,900000000000000000000000000000000000000000000000000000000000003525.9999999999 +3526,900000000000000000000000000000000000000000000000000000000000003526.9999999999 +3527,900000000000000000000000000000000000000000000000000000000000003527.9999999999 +3528,900000000000000000000000000000000000000000000000000000000000003528.9999999999 +3529,900000000000000000000000000000000000000000000000000000000000003529.9999999999 +3530,900000000000000000000000000000000000000000000000000000000000003530.9999999999 +3531,900000000000000000000000000000000000000000000000000000000000003531.9999999999 +3532,900000000000000000000000000000000000000000000000000000000000003532.9999999999 +3533,900000000000000000000000000000000000000000000000000000000000003533.9999999999 +3534,900000000000000000000000000000000000000000000000000000000000003534.9999999999 +3535,900000000000000000000000000000000000000000000000000000000000003535.9999999999 +3536,900000000000000000000000000000000000000000000000000000000000003536.9999999999 +3537,900000000000000000000000000000000000000000000000000000000000003537.9999999999 +3538,900000000000000000000000000000000000000000000000000000000000003538.9999999999 +3539,900000000000000000000000000000000000000000000000000000000000003539.9999999999 +3540,900000000000000000000000000000000000000000000000000000000000003540.9999999999 +3541,900000000000000000000000000000000000000000000000000000000000003541.9999999999 +3542,900000000000000000000000000000000000000000000000000000000000003542.9999999999 +3543,900000000000000000000000000000000000000000000000000000000000003543.9999999999 +3544,900000000000000000000000000000000000000000000000000000000000003544.9999999999 +3545,900000000000000000000000000000000000000000000000000000000000003545.9999999999 +3546,900000000000000000000000000000000000000000000000000000000000003546.9999999999 +3547,900000000000000000000000000000000000000000000000000000000000003547.9999999999 +3548,900000000000000000000000000000000000000000000000000000000000003548.9999999999 +3549,900000000000000000000000000000000000000000000000000000000000003549.9999999999 +3550,900000000000000000000000000000000000000000000000000000000000003550.9999999999 +3551,900000000000000000000000000000000000000000000000000000000000003551.9999999999 +3552,900000000000000000000000000000000000000000000000000000000000003552.9999999999 +3553,900000000000000000000000000000000000000000000000000000000000003553.9999999999 +3554,900000000000000000000000000000000000000000000000000000000000003554.9999999999 +3555,900000000000000000000000000000000000000000000000000000000000003555.9999999999 +3556,900000000000000000000000000000000000000000000000000000000000003556.9999999999 +3557,900000000000000000000000000000000000000000000000000000000000003557.9999999999 +3558,900000000000000000000000000000000000000000000000000000000000003558.9999999999 +3559,900000000000000000000000000000000000000000000000000000000000003559.9999999999 +3560,900000000000000000000000000000000000000000000000000000000000003560.9999999999 +3561,900000000000000000000000000000000000000000000000000000000000003561.9999999999 +3562,900000000000000000000000000000000000000000000000000000000000003562.9999999999 +3563,900000000000000000000000000000000000000000000000000000000000003563.9999999999 +3564,900000000000000000000000000000000000000000000000000000000000003564.9999999999 +3565,900000000000000000000000000000000000000000000000000000000000003565.9999999999 +3566,900000000000000000000000000000000000000000000000000000000000003566.9999999999 +3567,900000000000000000000000000000000000000000000000000000000000003567.9999999999 +3568,900000000000000000000000000000000000000000000000000000000000003568.9999999999 +3569,900000000000000000000000000000000000000000000000000000000000003569.9999999999 +3570,900000000000000000000000000000000000000000000000000000000000003570.9999999999 +3571,900000000000000000000000000000000000000000000000000000000000003571.9999999999 +3572,900000000000000000000000000000000000000000000000000000000000003572.9999999999 +3573,900000000000000000000000000000000000000000000000000000000000003573.9999999999 +3574,900000000000000000000000000000000000000000000000000000000000003574.9999999999 +3575,900000000000000000000000000000000000000000000000000000000000003575.9999999999 +3576,900000000000000000000000000000000000000000000000000000000000003576.9999999999 +3577,900000000000000000000000000000000000000000000000000000000000003577.9999999999 +3578,900000000000000000000000000000000000000000000000000000000000003578.9999999999 +3579,900000000000000000000000000000000000000000000000000000000000003579.9999999999 +3580,900000000000000000000000000000000000000000000000000000000000003580.9999999999 +3581,900000000000000000000000000000000000000000000000000000000000003581.9999999999 +3582,900000000000000000000000000000000000000000000000000000000000003582.9999999999 +3583,900000000000000000000000000000000000000000000000000000000000003583.9999999999 +3584,900000000000000000000000000000000000000000000000000000000000003584.9999999999 +3585,900000000000000000000000000000000000000000000000000000000000003585.9999999999 +3586,900000000000000000000000000000000000000000000000000000000000003586.9999999999 +3587,900000000000000000000000000000000000000000000000000000000000003587.9999999999 +3588,900000000000000000000000000000000000000000000000000000000000003588.9999999999 +3589,900000000000000000000000000000000000000000000000000000000000003589.9999999999 +3590,900000000000000000000000000000000000000000000000000000000000003590.9999999999 +3591,900000000000000000000000000000000000000000000000000000000000003591.9999999999 +3592,900000000000000000000000000000000000000000000000000000000000003592.9999999999 +3593,900000000000000000000000000000000000000000000000000000000000003593.9999999999 +3594,900000000000000000000000000000000000000000000000000000000000003594.9999999999 +3595,900000000000000000000000000000000000000000000000000000000000003595.9999999999 +3596,900000000000000000000000000000000000000000000000000000000000003596.9999999999 +3597,900000000000000000000000000000000000000000000000000000000000003597.9999999999 +3598,900000000000000000000000000000000000000000000000000000000000003598.9999999999 +3599,900000000000000000000000000000000000000000000000000000000000003599.9999999999 +3600,900000000000000000000000000000000000000000000000000000000000003600.9999999999 +3601,900000000000000000000000000000000000000000000000000000000000003601.9999999999 +3602,900000000000000000000000000000000000000000000000000000000000003602.9999999999 +3603,900000000000000000000000000000000000000000000000000000000000003603.9999999999 +3604,900000000000000000000000000000000000000000000000000000000000003604.9999999999 +3605,900000000000000000000000000000000000000000000000000000000000003605.9999999999 +3606,900000000000000000000000000000000000000000000000000000000000003606.9999999999 +3607,900000000000000000000000000000000000000000000000000000000000003607.9999999999 +3608,900000000000000000000000000000000000000000000000000000000000003608.9999999999 +3609,900000000000000000000000000000000000000000000000000000000000003609.9999999999 +3610,900000000000000000000000000000000000000000000000000000000000003610.9999999999 +3611,900000000000000000000000000000000000000000000000000000000000003611.9999999999 +3612,900000000000000000000000000000000000000000000000000000000000003612.9999999999 +3613,900000000000000000000000000000000000000000000000000000000000003613.9999999999 +3614,900000000000000000000000000000000000000000000000000000000000003614.9999999999 +3615,900000000000000000000000000000000000000000000000000000000000003615.9999999999 +3616,900000000000000000000000000000000000000000000000000000000000003616.9999999999 +3617,900000000000000000000000000000000000000000000000000000000000003617.9999999999 +3618,900000000000000000000000000000000000000000000000000000000000003618.9999999999 +3619,900000000000000000000000000000000000000000000000000000000000003619.9999999999 +3620,900000000000000000000000000000000000000000000000000000000000003620.9999999999 +3621,900000000000000000000000000000000000000000000000000000000000003621.9999999999 +3622,900000000000000000000000000000000000000000000000000000000000003622.9999999999 +3623,900000000000000000000000000000000000000000000000000000000000003623.9999999999 +3624,900000000000000000000000000000000000000000000000000000000000003624.9999999999 +3625,900000000000000000000000000000000000000000000000000000000000003625.9999999999 +3626,900000000000000000000000000000000000000000000000000000000000003626.9999999999 +3627,900000000000000000000000000000000000000000000000000000000000003627.9999999999 +3628,900000000000000000000000000000000000000000000000000000000000003628.9999999999 +3629,900000000000000000000000000000000000000000000000000000000000003629.9999999999 +3630,900000000000000000000000000000000000000000000000000000000000003630.9999999999 +3631,900000000000000000000000000000000000000000000000000000000000003631.9999999999 +3632,900000000000000000000000000000000000000000000000000000000000003632.9999999999 +3633,900000000000000000000000000000000000000000000000000000000000003633.9999999999 +3634,900000000000000000000000000000000000000000000000000000000000003634.9999999999 +3635,900000000000000000000000000000000000000000000000000000000000003635.9999999999 +3636,900000000000000000000000000000000000000000000000000000000000003636.9999999999 +3637,900000000000000000000000000000000000000000000000000000000000003637.9999999999 +3638,900000000000000000000000000000000000000000000000000000000000003638.9999999999 +3639,900000000000000000000000000000000000000000000000000000000000003639.9999999999 +3640,900000000000000000000000000000000000000000000000000000000000003640.9999999999 +3641,900000000000000000000000000000000000000000000000000000000000003641.9999999999 +3642,900000000000000000000000000000000000000000000000000000000000003642.9999999999 +3643,900000000000000000000000000000000000000000000000000000000000003643.9999999999 +3644,900000000000000000000000000000000000000000000000000000000000003644.9999999999 +3645,900000000000000000000000000000000000000000000000000000000000003645.9999999999 +3646,900000000000000000000000000000000000000000000000000000000000003646.9999999999 +3647,900000000000000000000000000000000000000000000000000000000000003647.9999999999 +3648,900000000000000000000000000000000000000000000000000000000000003648.9999999999 +3649,900000000000000000000000000000000000000000000000000000000000003649.9999999999 +3650,900000000000000000000000000000000000000000000000000000000000003650.9999999999 +3651,900000000000000000000000000000000000000000000000000000000000003651.9999999999 +3652,900000000000000000000000000000000000000000000000000000000000003652.9999999999 +3653,900000000000000000000000000000000000000000000000000000000000003653.9999999999 +3654,900000000000000000000000000000000000000000000000000000000000003654.9999999999 +3655,900000000000000000000000000000000000000000000000000000000000003655.9999999999 +3656,900000000000000000000000000000000000000000000000000000000000003656.9999999999 +3657,900000000000000000000000000000000000000000000000000000000000003657.9999999999 +3658,900000000000000000000000000000000000000000000000000000000000003658.9999999999 +3659,900000000000000000000000000000000000000000000000000000000000003659.9999999999 +3660,900000000000000000000000000000000000000000000000000000000000003660.9999999999 +3661,900000000000000000000000000000000000000000000000000000000000003661.9999999999 +3662,900000000000000000000000000000000000000000000000000000000000003662.9999999999 +3663,900000000000000000000000000000000000000000000000000000000000003663.9999999999 +3664,900000000000000000000000000000000000000000000000000000000000003664.9999999999 +3665,900000000000000000000000000000000000000000000000000000000000003665.9999999999 +3666,900000000000000000000000000000000000000000000000000000000000003666.9999999999 +3667,900000000000000000000000000000000000000000000000000000000000003667.9999999999 +3668,900000000000000000000000000000000000000000000000000000000000003668.9999999999 +3669,900000000000000000000000000000000000000000000000000000000000003669.9999999999 +3670,900000000000000000000000000000000000000000000000000000000000003670.9999999999 +3671,900000000000000000000000000000000000000000000000000000000000003671.9999999999 +3672,900000000000000000000000000000000000000000000000000000000000003672.9999999999 +3673,900000000000000000000000000000000000000000000000000000000000003673.9999999999 +3674,900000000000000000000000000000000000000000000000000000000000003674.9999999999 +3675,900000000000000000000000000000000000000000000000000000000000003675.9999999999 +3676,900000000000000000000000000000000000000000000000000000000000003676.9999999999 +3677,900000000000000000000000000000000000000000000000000000000000003677.9999999999 +3678,900000000000000000000000000000000000000000000000000000000000003678.9999999999 +3679,900000000000000000000000000000000000000000000000000000000000003679.9999999999 +3680,900000000000000000000000000000000000000000000000000000000000003680.9999999999 +3681,900000000000000000000000000000000000000000000000000000000000003681.9999999999 +3682,900000000000000000000000000000000000000000000000000000000000003682.9999999999 +3683,900000000000000000000000000000000000000000000000000000000000003683.9999999999 +3684,900000000000000000000000000000000000000000000000000000000000003684.9999999999 +3685,900000000000000000000000000000000000000000000000000000000000003685.9999999999 +3686,900000000000000000000000000000000000000000000000000000000000003686.9999999999 +3687,900000000000000000000000000000000000000000000000000000000000003687.9999999999 +3688,900000000000000000000000000000000000000000000000000000000000003688.9999999999 +3689,900000000000000000000000000000000000000000000000000000000000003689.9999999999 +3690,900000000000000000000000000000000000000000000000000000000000003690.9999999999 +3691,900000000000000000000000000000000000000000000000000000000000003691.9999999999 +3692,900000000000000000000000000000000000000000000000000000000000003692.9999999999 +3693,900000000000000000000000000000000000000000000000000000000000003693.9999999999 +3694,900000000000000000000000000000000000000000000000000000000000003694.9999999999 +3695,900000000000000000000000000000000000000000000000000000000000003695.9999999999 +3696,900000000000000000000000000000000000000000000000000000000000003696.9999999999 +3697,900000000000000000000000000000000000000000000000000000000000003697.9999999999 +3698,900000000000000000000000000000000000000000000000000000000000003698.9999999999 +3699,900000000000000000000000000000000000000000000000000000000000003699.9999999999 +3700,900000000000000000000000000000000000000000000000000000000000003700.9999999999 +3701,900000000000000000000000000000000000000000000000000000000000003701.9999999999 +3702,900000000000000000000000000000000000000000000000000000000000003702.9999999999 +3703,900000000000000000000000000000000000000000000000000000000000003703.9999999999 +3704,900000000000000000000000000000000000000000000000000000000000003704.9999999999 +3705,900000000000000000000000000000000000000000000000000000000000003705.9999999999 +3706,900000000000000000000000000000000000000000000000000000000000003706.9999999999 +3707,900000000000000000000000000000000000000000000000000000000000003707.9999999999 +3708,900000000000000000000000000000000000000000000000000000000000003708.9999999999 +3709,900000000000000000000000000000000000000000000000000000000000003709.9999999999 +3710,900000000000000000000000000000000000000000000000000000000000003710.9999999999 +3711,900000000000000000000000000000000000000000000000000000000000003711.9999999999 +3712,900000000000000000000000000000000000000000000000000000000000003712.9999999999 +3713,900000000000000000000000000000000000000000000000000000000000003713.9999999999 +3714,900000000000000000000000000000000000000000000000000000000000003714.9999999999 +3715,900000000000000000000000000000000000000000000000000000000000003715.9999999999 +3716,900000000000000000000000000000000000000000000000000000000000003716.9999999999 +3717,900000000000000000000000000000000000000000000000000000000000003717.9999999999 +3718,900000000000000000000000000000000000000000000000000000000000003718.9999999999 +3719,900000000000000000000000000000000000000000000000000000000000003719.9999999999 +3720,900000000000000000000000000000000000000000000000000000000000003720.9999999999 +3721,900000000000000000000000000000000000000000000000000000000000003721.9999999999 +3722,900000000000000000000000000000000000000000000000000000000000003722.9999999999 +3723,900000000000000000000000000000000000000000000000000000000000003723.9999999999 +3724,900000000000000000000000000000000000000000000000000000000000003724.9999999999 +3725,900000000000000000000000000000000000000000000000000000000000003725.9999999999 +3726,900000000000000000000000000000000000000000000000000000000000003726.9999999999 +3727,900000000000000000000000000000000000000000000000000000000000003727.9999999999 +3728,900000000000000000000000000000000000000000000000000000000000003728.9999999999 +3729,900000000000000000000000000000000000000000000000000000000000003729.9999999999 +3730,900000000000000000000000000000000000000000000000000000000000003730.9999999999 +3731,900000000000000000000000000000000000000000000000000000000000003731.9999999999 +3732,900000000000000000000000000000000000000000000000000000000000003732.9999999999 +3733,900000000000000000000000000000000000000000000000000000000000003733.9999999999 +3734,900000000000000000000000000000000000000000000000000000000000003734.9999999999 +3735,900000000000000000000000000000000000000000000000000000000000003735.9999999999 +3736,900000000000000000000000000000000000000000000000000000000000003736.9999999999 +3737,900000000000000000000000000000000000000000000000000000000000003737.9999999999 +3738,900000000000000000000000000000000000000000000000000000000000003738.9999999999 +3739,900000000000000000000000000000000000000000000000000000000000003739.9999999999 +3740,900000000000000000000000000000000000000000000000000000000000003740.9999999999 +3741,900000000000000000000000000000000000000000000000000000000000003741.9999999999 +3742,900000000000000000000000000000000000000000000000000000000000003742.9999999999 +3743,900000000000000000000000000000000000000000000000000000000000003743.9999999999 +3744,900000000000000000000000000000000000000000000000000000000000003744.9999999999 +3745,900000000000000000000000000000000000000000000000000000000000003745.9999999999 +3746,900000000000000000000000000000000000000000000000000000000000003746.9999999999 +3747,900000000000000000000000000000000000000000000000000000000000003747.9999999999 +3748,900000000000000000000000000000000000000000000000000000000000003748.9999999999 +3749,900000000000000000000000000000000000000000000000000000000000003749.9999999999 +3750,900000000000000000000000000000000000000000000000000000000000003750.9999999999 +3751,900000000000000000000000000000000000000000000000000000000000003751.9999999999 +3752,900000000000000000000000000000000000000000000000000000000000003752.9999999999 +3753,900000000000000000000000000000000000000000000000000000000000003753.9999999999 +3754,900000000000000000000000000000000000000000000000000000000000003754.9999999999 +3755,900000000000000000000000000000000000000000000000000000000000003755.9999999999 +3756,900000000000000000000000000000000000000000000000000000000000003756.9999999999 +3757,900000000000000000000000000000000000000000000000000000000000003757.9999999999 +3758,900000000000000000000000000000000000000000000000000000000000003758.9999999999 +3759,900000000000000000000000000000000000000000000000000000000000003759.9999999999 +3760,900000000000000000000000000000000000000000000000000000000000003760.9999999999 +3761,900000000000000000000000000000000000000000000000000000000000003761.9999999999 +3762,900000000000000000000000000000000000000000000000000000000000003762.9999999999 +3763,900000000000000000000000000000000000000000000000000000000000003763.9999999999 +3764,900000000000000000000000000000000000000000000000000000000000003764.9999999999 +3765,900000000000000000000000000000000000000000000000000000000000003765.9999999999 +3766,900000000000000000000000000000000000000000000000000000000000003766.9999999999 +3767,900000000000000000000000000000000000000000000000000000000000003767.9999999999 +3768,900000000000000000000000000000000000000000000000000000000000003768.9999999999 +3769,900000000000000000000000000000000000000000000000000000000000003769.9999999999 +3770,900000000000000000000000000000000000000000000000000000000000003770.9999999999 +3771,900000000000000000000000000000000000000000000000000000000000003771.9999999999 +3772,900000000000000000000000000000000000000000000000000000000000003772.9999999999 +3773,900000000000000000000000000000000000000000000000000000000000003773.9999999999 +3774,900000000000000000000000000000000000000000000000000000000000003774.9999999999 +3775,900000000000000000000000000000000000000000000000000000000000003775.9999999999 +3776,900000000000000000000000000000000000000000000000000000000000003776.9999999999 +3777,900000000000000000000000000000000000000000000000000000000000003777.9999999999 +3778,900000000000000000000000000000000000000000000000000000000000003778.9999999999 +3779,900000000000000000000000000000000000000000000000000000000000003779.9999999999 +3780,900000000000000000000000000000000000000000000000000000000000003780.9999999999 +3781,900000000000000000000000000000000000000000000000000000000000003781.9999999999 +3782,900000000000000000000000000000000000000000000000000000000000003782.9999999999 +3783,900000000000000000000000000000000000000000000000000000000000003783.9999999999 +3784,900000000000000000000000000000000000000000000000000000000000003784.9999999999 +3785,900000000000000000000000000000000000000000000000000000000000003785.9999999999 +3786,900000000000000000000000000000000000000000000000000000000000003786.9999999999 +3787,900000000000000000000000000000000000000000000000000000000000003787.9999999999 +3788,900000000000000000000000000000000000000000000000000000000000003788.9999999999 +3789,900000000000000000000000000000000000000000000000000000000000003789.9999999999 +3790,900000000000000000000000000000000000000000000000000000000000003790.9999999999 +3791,900000000000000000000000000000000000000000000000000000000000003791.9999999999 +3792,900000000000000000000000000000000000000000000000000000000000003792.9999999999 +3793,900000000000000000000000000000000000000000000000000000000000003793.9999999999 +3794,900000000000000000000000000000000000000000000000000000000000003794.9999999999 +3795,900000000000000000000000000000000000000000000000000000000000003795.9999999999 +3796,900000000000000000000000000000000000000000000000000000000000003796.9999999999 +3797,900000000000000000000000000000000000000000000000000000000000003797.9999999999 +3798,900000000000000000000000000000000000000000000000000000000000003798.9999999999 +3799,900000000000000000000000000000000000000000000000000000000000003799.9999999999 +3800,900000000000000000000000000000000000000000000000000000000000003800.9999999999 +3801,900000000000000000000000000000000000000000000000000000000000003801.9999999999 +3802,900000000000000000000000000000000000000000000000000000000000003802.9999999999 +3803,900000000000000000000000000000000000000000000000000000000000003803.9999999999 +3804,900000000000000000000000000000000000000000000000000000000000003804.9999999999 +3805,900000000000000000000000000000000000000000000000000000000000003805.9999999999 +3806,900000000000000000000000000000000000000000000000000000000000003806.9999999999 +3807,900000000000000000000000000000000000000000000000000000000000003807.9999999999 +3808,900000000000000000000000000000000000000000000000000000000000003808.9999999999 +3809,900000000000000000000000000000000000000000000000000000000000003809.9999999999 +3810,900000000000000000000000000000000000000000000000000000000000003810.9999999999 +3811,900000000000000000000000000000000000000000000000000000000000003811.9999999999 +3812,900000000000000000000000000000000000000000000000000000000000003812.9999999999 +3813,900000000000000000000000000000000000000000000000000000000000003813.9999999999 +3814,900000000000000000000000000000000000000000000000000000000000003814.9999999999 +3815,900000000000000000000000000000000000000000000000000000000000003815.9999999999 +3816,900000000000000000000000000000000000000000000000000000000000003816.9999999999 +3817,900000000000000000000000000000000000000000000000000000000000003817.9999999999 +3818,900000000000000000000000000000000000000000000000000000000000003818.9999999999 +3819,900000000000000000000000000000000000000000000000000000000000003819.9999999999 +3820,900000000000000000000000000000000000000000000000000000000000003820.9999999999 +3821,900000000000000000000000000000000000000000000000000000000000003821.9999999999 +3822,900000000000000000000000000000000000000000000000000000000000003822.9999999999 +3823,900000000000000000000000000000000000000000000000000000000000003823.9999999999 +3824,900000000000000000000000000000000000000000000000000000000000003824.9999999999 +3825,900000000000000000000000000000000000000000000000000000000000003825.9999999999 +3826,900000000000000000000000000000000000000000000000000000000000003826.9999999999 +3827,900000000000000000000000000000000000000000000000000000000000003827.9999999999 +3828,900000000000000000000000000000000000000000000000000000000000003828.9999999999 +3829,900000000000000000000000000000000000000000000000000000000000003829.9999999999 +3830,900000000000000000000000000000000000000000000000000000000000003830.9999999999 +3831,900000000000000000000000000000000000000000000000000000000000003831.9999999999 +3832,900000000000000000000000000000000000000000000000000000000000003832.9999999999 +3833,900000000000000000000000000000000000000000000000000000000000003833.9999999999 +3834,900000000000000000000000000000000000000000000000000000000000003834.9999999999 +3835,900000000000000000000000000000000000000000000000000000000000003835.9999999999 +3836,900000000000000000000000000000000000000000000000000000000000003836.9999999999 +3837,900000000000000000000000000000000000000000000000000000000000003837.9999999999 +3838,900000000000000000000000000000000000000000000000000000000000003838.9999999999 +3839,900000000000000000000000000000000000000000000000000000000000003839.9999999999 +3840,900000000000000000000000000000000000000000000000000000000000003840.9999999999 +3841,900000000000000000000000000000000000000000000000000000000000003841.9999999999 +3842,900000000000000000000000000000000000000000000000000000000000003842.9999999999 +3843,900000000000000000000000000000000000000000000000000000000000003843.9999999999 +3844,900000000000000000000000000000000000000000000000000000000000003844.9999999999 +3845,900000000000000000000000000000000000000000000000000000000000003845.9999999999 +3846,900000000000000000000000000000000000000000000000000000000000003846.9999999999 +3847,900000000000000000000000000000000000000000000000000000000000003847.9999999999 +3848,900000000000000000000000000000000000000000000000000000000000003848.9999999999 +3849,900000000000000000000000000000000000000000000000000000000000003849.9999999999 +3850,900000000000000000000000000000000000000000000000000000000000003850.9999999999 +3851,900000000000000000000000000000000000000000000000000000000000003851.9999999999 +3852,900000000000000000000000000000000000000000000000000000000000003852.9999999999 +3853,900000000000000000000000000000000000000000000000000000000000003853.9999999999 +3854,900000000000000000000000000000000000000000000000000000000000003854.9999999999 +3855,900000000000000000000000000000000000000000000000000000000000003855.9999999999 +3856,900000000000000000000000000000000000000000000000000000000000003856.9999999999 +3857,900000000000000000000000000000000000000000000000000000000000003857.9999999999 +3858,900000000000000000000000000000000000000000000000000000000000003858.9999999999 +3859,900000000000000000000000000000000000000000000000000000000000003859.9999999999 +3860,900000000000000000000000000000000000000000000000000000000000003860.9999999999 +3861,900000000000000000000000000000000000000000000000000000000000003861.9999999999 +3862,900000000000000000000000000000000000000000000000000000000000003862.9999999999 +3863,900000000000000000000000000000000000000000000000000000000000003863.9999999999 +3864,900000000000000000000000000000000000000000000000000000000000003864.9999999999 +3865,900000000000000000000000000000000000000000000000000000000000003865.9999999999 +3866,900000000000000000000000000000000000000000000000000000000000003866.9999999999 +3867,900000000000000000000000000000000000000000000000000000000000003867.9999999999 +3868,900000000000000000000000000000000000000000000000000000000000003868.9999999999 +3869,900000000000000000000000000000000000000000000000000000000000003869.9999999999 +3870,900000000000000000000000000000000000000000000000000000000000003870.9999999999 +3871,900000000000000000000000000000000000000000000000000000000000003871.9999999999 +3872,900000000000000000000000000000000000000000000000000000000000003872.9999999999 +3873,900000000000000000000000000000000000000000000000000000000000003873.9999999999 +3874,900000000000000000000000000000000000000000000000000000000000003874.9999999999 +3875,900000000000000000000000000000000000000000000000000000000000003875.9999999999 +3876,900000000000000000000000000000000000000000000000000000000000003876.9999999999 +3877,900000000000000000000000000000000000000000000000000000000000003877.9999999999 +3878,900000000000000000000000000000000000000000000000000000000000003878.9999999999 +3879,900000000000000000000000000000000000000000000000000000000000003879.9999999999 +3880,900000000000000000000000000000000000000000000000000000000000003880.9999999999 +3881,900000000000000000000000000000000000000000000000000000000000003881.9999999999 +3882,900000000000000000000000000000000000000000000000000000000000003882.9999999999 +3883,900000000000000000000000000000000000000000000000000000000000003883.9999999999 +3884,900000000000000000000000000000000000000000000000000000000000003884.9999999999 +3885,900000000000000000000000000000000000000000000000000000000000003885.9999999999 +3886,900000000000000000000000000000000000000000000000000000000000003886.9999999999 +3887,900000000000000000000000000000000000000000000000000000000000003887.9999999999 +3888,900000000000000000000000000000000000000000000000000000000000003888.9999999999 +3889,900000000000000000000000000000000000000000000000000000000000003889.9999999999 +3890,900000000000000000000000000000000000000000000000000000000000003890.9999999999 +3891,900000000000000000000000000000000000000000000000000000000000003891.9999999999 +3892,900000000000000000000000000000000000000000000000000000000000003892.9999999999 +3893,900000000000000000000000000000000000000000000000000000000000003893.9999999999 +3894,900000000000000000000000000000000000000000000000000000000000003894.9999999999 +3895,900000000000000000000000000000000000000000000000000000000000003895.9999999999 +3896,900000000000000000000000000000000000000000000000000000000000003896.9999999999 +3897,900000000000000000000000000000000000000000000000000000000000003897.9999999999 +3898,900000000000000000000000000000000000000000000000000000000000003898.9999999999 +3899,900000000000000000000000000000000000000000000000000000000000003899.9999999999 +3900,900000000000000000000000000000000000000000000000000000000000003900.9999999999 +3901,900000000000000000000000000000000000000000000000000000000000003901.9999999999 +3902,900000000000000000000000000000000000000000000000000000000000003902.9999999999 +3903,900000000000000000000000000000000000000000000000000000000000003903.9999999999 +3904,900000000000000000000000000000000000000000000000000000000000003904.9999999999 +3905,900000000000000000000000000000000000000000000000000000000000003905.9999999999 +3906,900000000000000000000000000000000000000000000000000000000000003906.9999999999 +3907,900000000000000000000000000000000000000000000000000000000000003907.9999999999 +3908,900000000000000000000000000000000000000000000000000000000000003908.9999999999 +3909,900000000000000000000000000000000000000000000000000000000000003909.9999999999 +3910,900000000000000000000000000000000000000000000000000000000000003910.9999999999 +3911,900000000000000000000000000000000000000000000000000000000000003911.9999999999 +3912,900000000000000000000000000000000000000000000000000000000000003912.9999999999 +3913,900000000000000000000000000000000000000000000000000000000000003913.9999999999 +3914,900000000000000000000000000000000000000000000000000000000000003914.9999999999 +3915,900000000000000000000000000000000000000000000000000000000000003915.9999999999 +3916,900000000000000000000000000000000000000000000000000000000000003916.9999999999 +3917,900000000000000000000000000000000000000000000000000000000000003917.9999999999 +3918,900000000000000000000000000000000000000000000000000000000000003918.9999999999 +3919,900000000000000000000000000000000000000000000000000000000000003919.9999999999 +3920,900000000000000000000000000000000000000000000000000000000000003920.9999999999 +3921,900000000000000000000000000000000000000000000000000000000000003921.9999999999 +3922,900000000000000000000000000000000000000000000000000000000000003922.9999999999 +3923,900000000000000000000000000000000000000000000000000000000000003923.9999999999 +3924,900000000000000000000000000000000000000000000000000000000000003924.9999999999 +3925,900000000000000000000000000000000000000000000000000000000000003925.9999999999 +3926,900000000000000000000000000000000000000000000000000000000000003926.9999999999 +3927,900000000000000000000000000000000000000000000000000000000000003927.9999999999 +3928,900000000000000000000000000000000000000000000000000000000000003928.9999999999 +3929,900000000000000000000000000000000000000000000000000000000000003929.9999999999 +3930,900000000000000000000000000000000000000000000000000000000000003930.9999999999 +3931,900000000000000000000000000000000000000000000000000000000000003931.9999999999 +3932,900000000000000000000000000000000000000000000000000000000000003932.9999999999 +3933,900000000000000000000000000000000000000000000000000000000000003933.9999999999 +3934,900000000000000000000000000000000000000000000000000000000000003934.9999999999 +3935,900000000000000000000000000000000000000000000000000000000000003935.9999999999 +3936,900000000000000000000000000000000000000000000000000000000000003936.9999999999 +3937,900000000000000000000000000000000000000000000000000000000000003937.9999999999 +3938,900000000000000000000000000000000000000000000000000000000000003938.9999999999 +3939,900000000000000000000000000000000000000000000000000000000000003939.9999999999 +3940,900000000000000000000000000000000000000000000000000000000000003940.9999999999 +3941,900000000000000000000000000000000000000000000000000000000000003941.9999999999 +3942,900000000000000000000000000000000000000000000000000000000000003942.9999999999 +3943,900000000000000000000000000000000000000000000000000000000000003943.9999999999 +3944,900000000000000000000000000000000000000000000000000000000000003944.9999999999 +3945,900000000000000000000000000000000000000000000000000000000000003945.9999999999 +3946,900000000000000000000000000000000000000000000000000000000000003946.9999999999 +3947,900000000000000000000000000000000000000000000000000000000000003947.9999999999 +3948,900000000000000000000000000000000000000000000000000000000000003948.9999999999 +3949,900000000000000000000000000000000000000000000000000000000000003949.9999999999 +3950,900000000000000000000000000000000000000000000000000000000000003950.9999999999 +3951,900000000000000000000000000000000000000000000000000000000000003951.9999999999 +3952,900000000000000000000000000000000000000000000000000000000000003952.9999999999 +3953,900000000000000000000000000000000000000000000000000000000000003953.9999999999 +3954,900000000000000000000000000000000000000000000000000000000000003954.9999999999 +3955,900000000000000000000000000000000000000000000000000000000000003955.9999999999 +3956,900000000000000000000000000000000000000000000000000000000000003956.9999999999 +3957,900000000000000000000000000000000000000000000000000000000000003957.9999999999 +3958,900000000000000000000000000000000000000000000000000000000000003958.9999999999 +3959,900000000000000000000000000000000000000000000000000000000000003959.9999999999 +3960,900000000000000000000000000000000000000000000000000000000000003960.9999999999 +3961,900000000000000000000000000000000000000000000000000000000000003961.9999999999 +3962,900000000000000000000000000000000000000000000000000000000000003962.9999999999 +3963,900000000000000000000000000000000000000000000000000000000000003963.9999999999 +3964,900000000000000000000000000000000000000000000000000000000000003964.9999999999 +3965,900000000000000000000000000000000000000000000000000000000000003965.9999999999 +3966,900000000000000000000000000000000000000000000000000000000000003966.9999999999 +3967,900000000000000000000000000000000000000000000000000000000000003967.9999999999 +3968,900000000000000000000000000000000000000000000000000000000000003968.9999999999 +3969,900000000000000000000000000000000000000000000000000000000000003969.9999999999 +3970,900000000000000000000000000000000000000000000000000000000000003970.9999999999 +3971,900000000000000000000000000000000000000000000000000000000000003971.9999999999 +3972,900000000000000000000000000000000000000000000000000000000000003972.9999999999 +3973,900000000000000000000000000000000000000000000000000000000000003973.9999999999 +3974,900000000000000000000000000000000000000000000000000000000000003974.9999999999 +3975,900000000000000000000000000000000000000000000000000000000000003975.9999999999 +3976,900000000000000000000000000000000000000000000000000000000000003976.9999999999 +3977,900000000000000000000000000000000000000000000000000000000000003977.9999999999 +3978,900000000000000000000000000000000000000000000000000000000000003978.9999999999 +3979,900000000000000000000000000000000000000000000000000000000000003979.9999999999 +3980,900000000000000000000000000000000000000000000000000000000000003980.9999999999 +3981,900000000000000000000000000000000000000000000000000000000000003981.9999999999 +3982,900000000000000000000000000000000000000000000000000000000000003982.9999999999 +3983,900000000000000000000000000000000000000000000000000000000000003983.9999999999 +3984,900000000000000000000000000000000000000000000000000000000000003984.9999999999 +3985,900000000000000000000000000000000000000000000000000000000000003985.9999999999 +3986,900000000000000000000000000000000000000000000000000000000000003986.9999999999 +3987,900000000000000000000000000000000000000000000000000000000000003987.9999999999 +3988,900000000000000000000000000000000000000000000000000000000000003988.9999999999 +3989,900000000000000000000000000000000000000000000000000000000000003989.9999999999 +3990,900000000000000000000000000000000000000000000000000000000000003990.9999999999 +3991,900000000000000000000000000000000000000000000000000000000000003991.9999999999 +3992,900000000000000000000000000000000000000000000000000000000000003992.9999999999 +3993,900000000000000000000000000000000000000000000000000000000000003993.9999999999 +3994,900000000000000000000000000000000000000000000000000000000000003994.9999999999 +3995,900000000000000000000000000000000000000000000000000000000000003995.9999999999 +3996,900000000000000000000000000000000000000000000000000000000000003996.9999999999 +3997,900000000000000000000000000000000000000000000000000000000000003997.9999999999 +3998,900000000000000000000000000000000000000000000000000000000000003998.9999999999 +3999,900000000000000000000000000000000000000000000000000000000000003999.9999999999 +4000,900000000000000000000000000000000000000000000000000000000000004000.9999999999 +4001,900000000000000000000000000000000000000000000000000000000000004001.9999999999 +4002,900000000000000000000000000000000000000000000000000000000000004002.9999999999 +4003,900000000000000000000000000000000000000000000000000000000000004003.9999999999 +4004,900000000000000000000000000000000000000000000000000000000000004004.9999999999 +4005,900000000000000000000000000000000000000000000000000000000000004005.9999999999 +4006,900000000000000000000000000000000000000000000000000000000000004006.9999999999 +4007,900000000000000000000000000000000000000000000000000000000000004007.9999999999 +4008,900000000000000000000000000000000000000000000000000000000000004008.9999999999 +4009,900000000000000000000000000000000000000000000000000000000000004009.9999999999 +4010,900000000000000000000000000000000000000000000000000000000000004010.9999999999 +4011,900000000000000000000000000000000000000000000000000000000000004011.9999999999 +4012,900000000000000000000000000000000000000000000000000000000000004012.9999999999 +4013,900000000000000000000000000000000000000000000000000000000000004013.9999999999 +4014,900000000000000000000000000000000000000000000000000000000000004014.9999999999 +4015,900000000000000000000000000000000000000000000000000000000000004015.9999999999 +4016,900000000000000000000000000000000000000000000000000000000000004016.9999999999 +4017,900000000000000000000000000000000000000000000000000000000000004017.9999999999 +4018,900000000000000000000000000000000000000000000000000000000000004018.9999999999 +4019,900000000000000000000000000000000000000000000000000000000000004019.9999999999 +4020,900000000000000000000000000000000000000000000000000000000000004020.9999999999 +4021,900000000000000000000000000000000000000000000000000000000000004021.9999999999 +4022,900000000000000000000000000000000000000000000000000000000000004022.9999999999 +4023,900000000000000000000000000000000000000000000000000000000000004023.9999999999 +4024,900000000000000000000000000000000000000000000000000000000000004024.9999999999 +4025,900000000000000000000000000000000000000000000000000000000000004025.9999999999 +4026,900000000000000000000000000000000000000000000000000000000000004026.9999999999 +4027,900000000000000000000000000000000000000000000000000000000000004027.9999999999 +4028,900000000000000000000000000000000000000000000000000000000000004028.9999999999 +4029,900000000000000000000000000000000000000000000000000000000000004029.9999999999 +4030,900000000000000000000000000000000000000000000000000000000000004030.9999999999 +4031,900000000000000000000000000000000000000000000000000000000000004031.9999999999 +4032,900000000000000000000000000000000000000000000000000000000000004032.9999999999 +4033,900000000000000000000000000000000000000000000000000000000000004033.9999999999 +4034,900000000000000000000000000000000000000000000000000000000000004034.9999999999 +4035,900000000000000000000000000000000000000000000000000000000000004035.9999999999 +4036,900000000000000000000000000000000000000000000000000000000000004036.9999999999 +4037,900000000000000000000000000000000000000000000000000000000000004037.9999999999 +4038,900000000000000000000000000000000000000000000000000000000000004038.9999999999 +4039,900000000000000000000000000000000000000000000000000000000000004039.9999999999 +4040,900000000000000000000000000000000000000000000000000000000000004040.9999999999 +4041,900000000000000000000000000000000000000000000000000000000000004041.9999999999 +4042,900000000000000000000000000000000000000000000000000000000000004042.9999999999 +4043,900000000000000000000000000000000000000000000000000000000000004043.9999999999 +4044,900000000000000000000000000000000000000000000000000000000000004044.9999999999 +4045,900000000000000000000000000000000000000000000000000000000000004045.9999999999 +4046,900000000000000000000000000000000000000000000000000000000000004046.9999999999 +4047,900000000000000000000000000000000000000000000000000000000000004047.9999999999 +4048,900000000000000000000000000000000000000000000000000000000000004048.9999999999 +4049,900000000000000000000000000000000000000000000000000000000000004049.9999999999 +4050,900000000000000000000000000000000000000000000000000000000000004050.9999999999 +4051,900000000000000000000000000000000000000000000000000000000000004051.9999999999 +4052,900000000000000000000000000000000000000000000000000000000000004052.9999999999 +4053,900000000000000000000000000000000000000000000000000000000000004053.9999999999 +4054,900000000000000000000000000000000000000000000000000000000000004054.9999999999 +4055,900000000000000000000000000000000000000000000000000000000000004055.9999999999 +4056,900000000000000000000000000000000000000000000000000000000000004056.9999999999 +4057,900000000000000000000000000000000000000000000000000000000000004057.9999999999 +4058,900000000000000000000000000000000000000000000000000000000000004058.9999999999 +4059,900000000000000000000000000000000000000000000000000000000000004059.9999999999 +4060,900000000000000000000000000000000000000000000000000000000000004060.9999999999 +4061,900000000000000000000000000000000000000000000000000000000000004061.9999999999 +4062,900000000000000000000000000000000000000000000000000000000000004062.9999999999 +4063,900000000000000000000000000000000000000000000000000000000000004063.9999999999 +4064,900000000000000000000000000000000000000000000000000000000000004064.9999999999 +4065,900000000000000000000000000000000000000000000000000000000000004065.9999999999 +4066,900000000000000000000000000000000000000000000000000000000000004066.9999999999 +4067,900000000000000000000000000000000000000000000000000000000000004067.9999999999 +4068,900000000000000000000000000000000000000000000000000000000000004068.9999999999 +4069,900000000000000000000000000000000000000000000000000000000000004069.9999999999 +4070,900000000000000000000000000000000000000000000000000000000000004070.9999999999 +4071,900000000000000000000000000000000000000000000000000000000000004071.9999999999 +4072,900000000000000000000000000000000000000000000000000000000000004072.9999999999 +4073,900000000000000000000000000000000000000000000000000000000000004073.9999999999 +4074,900000000000000000000000000000000000000000000000000000000000004074.9999999999 +4075,900000000000000000000000000000000000000000000000000000000000004075.9999999999 +4076,900000000000000000000000000000000000000000000000000000000000004076.9999999999 +4077,900000000000000000000000000000000000000000000000000000000000004077.9999999999 +4078,900000000000000000000000000000000000000000000000000000000000004078.9999999999 +4079,900000000000000000000000000000000000000000000000000000000000004079.9999999999 +4080,900000000000000000000000000000000000000000000000000000000000004080.9999999999 +4081,900000000000000000000000000000000000000000000000000000000000004081.9999999999 +4082,900000000000000000000000000000000000000000000000000000000000004082.9999999999 +4083,900000000000000000000000000000000000000000000000000000000000004083.9999999999 +4084,900000000000000000000000000000000000000000000000000000000000004084.9999999999 +4085,900000000000000000000000000000000000000000000000000000000000004085.9999999999 +4086,900000000000000000000000000000000000000000000000000000000000004086.9999999999 +4087,900000000000000000000000000000000000000000000000000000000000004087.9999999999 +4088,900000000000000000000000000000000000000000000000000000000000004088.9999999999 +4089,900000000000000000000000000000000000000000000000000000000000004089.9999999999 +4090,900000000000000000000000000000000000000000000000000000000000004090.9999999999 +4091,900000000000000000000000000000000000000000000000000000000000004091.9999999999 +4092,900000000000000000000000000000000000000000000000000000000000004092.9999999999 +4093,900000000000000000000000000000000000000000000000000000000000004093.9999999999 +4094,900000000000000000000000000000000000000000000000000000000000004094.9999999999 +4095,900000000000000000000000000000000000000000000000000000000000004095.9999999999 +4096,900000000000000000000000000000000000000000000000000000000000004096.9999999999 diff --git a/regression-test/data/datatype_p0/decimalv3/test_predicate.out b/regression-test/data/datatype_p0/decimalv3/test_predicate.out index ab074a78d7956e..1456180d7a4685 100644 --- a/regression-test/data/datatype_p0/decimalv3/test_predicate.out +++ b/regression-test/data/datatype_p0/decimalv3/test_predicate.out @@ -88,3 +88,37 @@ false 3.000000 33333333333333333333333333333333.333333 33333333333333333333333333333333.333333 4.444444 2.222222 3.333333 +-- !decimal256_select_all2 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !decimal256_predicate_6 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !decimal256_predicate_7 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !decimal256_predicate_8 -- +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !decimal256_predicate_9 -- +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !decimal256_predicate_10 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 + +-- !decimal256_predicate_11 -- +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !decimal256_predicate_12 -- +1.000000000 999999999999999999999999999999999999999999999999999999999999999999.9999999999 99999999999999999999999999999999999999999999999999999999999999999.99999999999 +3.000000000 333333333333333333333333333333333333333333333333333333333333333333.3333333333 33333333333333333333333333333333333333333333333333333333333333333.33333333333 + +-- !decimal256_predicate_13 -- +2.000000000 499999999999999999999999999999999999999999999999999999999999999999.9999999999 49999999999999999999999999999999999999999999999999999999999999999.99999999999 + diff --git a/regression-test/suites/datatype_p0/decimalv3/test_arithmetic_expressions.groovy b/regression-test/suites/datatype_p0/decimalv3/test_arithmetic_expressions.groovy index cfac94774f6d5c..d6784e3dbd0081 100644 --- a/regression-test/suites/datatype_p0/decimalv3/test_arithmetic_expressions.groovy +++ b/regression-test/suites/datatype_p0/decimalv3/test_arithmetic_expressions.groovy @@ -137,6 +137,7 @@ suite("test_arithmetic_expressions") { (2, 499999999999.999999, 499999999999.999999), (3, 333333333333.333333, 333333333333.333333), (4, 4, 4);""" + sql "sync" // TODO: fix decimal cast // sql "select k3, CAST(k3 AS DECIMALV3(18, 10)) from test_arithmetic_expressions_64;" /* @@ -166,20 +167,20 @@ mysql [test]>select k3, CAST(k3 AS DECIMALV3(18, 10)) from test_arithmetic_expre "replication_allocation" = "tag.location.default: 1" ); """ - sql """insert into test_arithmetic_expressions_128_1 values(1, 99999999999999999999999999999999.999999, 99999999999999999999999999999999.999999), + sql """insert into test_arithmetic_expressions_128_1 values + (1, 99999999999999999999999999999999.999999, 99999999999999999999999999999999.999999), (2, 49999999999999999999999999999999.999999, 49999999999999999999999999999999.999999), (3, 33333333333333333333333333333333.333333, 33333333333333333333333333333333.333333), (4.444444, 2.222222, 3.333333);""" + sql "sync" qt_decimal128_select_all "select * from test_arithmetic_expressions_128_1 order by k1, k2;" - // fix cast // qt_decimal128_cast "select k3, CAST(k3 AS DECIMALV3(38, 10)) from test_arithmetic_expressions_128_1 order by 1, 2;" - /* + // int128 multiply overflow qt_decimal128_multiply_0 "select k1 * k2 a from test_arithmetic_expressions_128_1 order by 1;" qt_decimal128_arith_union "select * from (select k1 * k2 from test_arithmetic_expressions_128_1 union all select k3 from test_arithmetic_expressions_128_1) a order by 1" qt_decimal128_multiply_1 "select k1 * k2 * k3 a from test_arithmetic_expressions_128_1 order by 1;" qt_decimal128_multiply_2 "select k1 * k2 * k3 * k1 * k2 * k3 from test_arithmetic_expressions_128_1 order by k1" qt_decimal128_multiply_div "select k1 * k2 / k3 * k1 * k2 * k3 from test_arithmetic_expressions_128_1 order by k1" - */ sql "DROP TABLE IF EXISTS `test_arithmetic_expressions_128_2`"; sql """ @@ -201,16 +202,27 @@ mysql [test]>select k3, CAST(k3 AS DECIMALV3(18, 10)) from test_arithmetic_expre sql """ insert into test_arithmetic_expressions_128_2 values(999999.999,999999.999,999999.999,999999.999,999999.999,999999.999,999999.999,999999.999,999999.999,999999.999,999999.999); """ + sql "sync" qt_decimal128_select_all_2 "select * from test_arithmetic_expressions_128_2 order by a" - /* qt_decimal128_mixed_calc_0 "select a + b + c from test_arithmetic_expressions_128_2;" qt_decimal128_mixed_calc_1 "select (a + b + c) * d from test_arithmetic_expressions_128_2;" qt_decimal128_mixed_calc_2 "select (a + b + c) / d from test_arithmetic_expressions_128_2;" qt_decimal128_mixed_calc_3 "select a + b + c + d + e + f + g + h + i + j + k from test_arithmetic_expressions_128_2;" - */ sql "set enable_nereids_planner = true;" sql "set enable_decimal256 = true;" + + qt_decimal128_enable_decimal256_multiply_0 "select k1 * k2 a from test_arithmetic_expressions_128_1 order by 1;" + qt_decimal128_enable_decimal256_arith_union "select * from (select k1 * k2 from test_arithmetic_expressions_128_1 union all select k3 from test_arithmetic_expressions_128_1) a order by 1" + qt_decimal128_enable_decimal256_multiply_1 "select k1 * k2 * k3 from test_arithmetic_expressions_128_1 order by 1;" + qt_decimal128_enable_decimal256_multiply_2 "select k1 * k2 * k3 * k1 * k2 * k3 from test_arithmetic_expressions_128_1 order by k1" + qt_decimal128_enable_decimal256_multiply_div "select k1 * k2 / k3 * k1 * k2 * k3 from test_arithmetic_expressions_128_1 order by k1" + + qt_decimal128_enable_decimal256_mixed_calc_0 "select a + b + c from test_arithmetic_expressions_128_2;" + qt_decimal128_enable_decimal256_mixed_calc_1 "select (a + b + c) * d from test_arithmetic_expressions_128_2;" + qt_decimal128_enable_decimal256_mixed_calc_2 "select (a + b + c) / d from test_arithmetic_expressions_128_2;" + qt_decimal128_enable_decimal256_mixed_calc_3 "select a + b + c + d + e + f + g + h + i + j + k from test_arithmetic_expressions_128_2;" + qt_decimal128_cast256_cast "select k3, CAST(k3 AS DECIMALV3(76, 10)) from test_arithmetic_expressions_128_1 order by 1, 2;" qt_decimal128_cast256_calc_0 "select cast(k1 as decimalv3(76, 6)) + k2 a from test_arithmetic_expressions_128_1 order by 1;" qt_decimal128_cast256_calc_1 "select cast(k2 as decimalv3(76, 6)) - k1 a from test_arithmetic_expressions_128_1 order by 1;" @@ -258,7 +270,6 @@ mysql [test]>select k3, CAST(k3 AS DECIMALV3(38, 10)) from test_arithmetic_expre | -5151654377011498561003149524047726679019988040430007836382.4035124889496445184 | +---------------------------------------------------------------------------------+ */ - /* sql "DROP TABLE IF EXISTS `test_arithmetic_expressions_256_1`" sql """ CREATE TABLE IF NOT EXISTS `test_arithmetic_expressions_256_1` ( @@ -266,15 +277,18 @@ mysql [test]>select k3, CAST(k3 AS DECIMALV3(38, 10)) from test_arithmetic_expre `k2` decimalv3(76, 10) NULL COMMENT "", `k3` decimalv3(76, 11) NULL COMMENT "" ) ENGINE=OLAP - DISTRIBUTED BY HASH(`k1`, `k2`, `k3`) BUCKETS 8 + DUPLICATE KEY(`k1`) + DISTRIBUTED BY HASH(`k1`) BUCKETS 8 PROPERTIES ( "replication_allocation" = "tag.location.default: 1" ); """ - sql """insert into test_arithmetic_expressions_256_1 values(1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + sql """insert into test_arithmetic_expressions_256_1 values + (1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), (2, 499999999999999999999999999999999999999999999999999999999999999999.9999999999, 49999999999999999999999999999999999999999999999999999999999999999.99999999999), (3, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333);""" + sql "sync" qt_decimal256_arith_select_all "select * from test_arithmetic_expressions_256_1 order by k1, k2, k3;" qt_decimal256_arith_plus "select k1 + k2 from test_arithmetic_expressions_256_1 order by 1;" qt_decimal256_arith_minus "select k2 - k1 from test_arithmetic_expressions_256_1 order by 1;" @@ -308,6 +322,7 @@ mysql [test]>select k3, CAST(k3 AS DECIMALV3(38, 10)) from test_arithmetic_expre sql """ insert into test_arithmetic_expressions_256_2 values(999999.999,999999.999,999999.999,999999.999,999999.999,999999.999,999999.999,999999.999,999999.999,999999.999,999999.999); """ + sql "sync" qt_decimal256_select_all_2 "select * from test_arithmetic_expressions_256_2 order by a" qt_decimal256_mixed_calc_0 "select a + b + c from test_arithmetic_expressions_256_2;" @@ -330,6 +345,7 @@ mysql [test]>select k3, CAST(k3 AS DECIMALV3(38, 10)) from test_arithmetic_expre sql """insert into test_arithmetic_expressions_256_3 values(1, 999999999999999999999999999999999999999999999999999999999999999999999999999.9, 99999999999999999999999999999999999999999999999999999999999999999999999999.99), (2, 499999999999999999999999999999999999999999999999999999999999999999999999999.9, 49999999999999999999999999999999999999999999999999999999999999999999999999.99), (3, 333333333333333333333333333333333333333333333333333333333333333333333333333.3, 33333333333333333333333333333333333333333333333333333333333333333333333333.33);""" + sql "sync" qt_decimal256_arith_3 "select k1, k2, k1 * k2 a from test_arithmetic_expressions_256_3 order by k1, k2;" sql "DROP TABLE IF EXISTS `test_arithmetic_expressions_256_4`" @@ -348,6 +364,7 @@ mysql [test]>select k3, CAST(k3 AS DECIMALV3(38, 10)) from test_arithmetic_expre sql """ insert into test_arithmetic_expressions_256_4 values (2,107684988.257976000,107684988.257976000,148981.0000000000); """ sql """ insert into test_arithmetic_expressions_256_4 values (3,76891560.464178000,76891560.464178000,106161.0000000000); """ sql """ insert into test_arithmetic_expressions_256_4 values (4,277170831.851350000,277170831.851350000,402344.0000000000); """ + sql "sync" qt_decimal256_div_v2_v3 """ select id, fz/fm as dec,fzv3/fm as decv3 from test_arithmetic_expressions_256_4 ORDER BY id; """ @@ -367,8 +384,8 @@ mysql [test]>select k3, CAST(k3 AS DECIMALV3(38, 10)) from test_arithmetic_expre sql """ insert into test_arithmetic_expressions_256_5 values (2,107684988.257976000,3,3); """ sql """ insert into test_arithmetic_expressions_256_5 values (3,76891560.464178000,5,5); """ sql """ insert into test_arithmetic_expressions_256_5 values (4,277170831.851350000,7,7); """ + sql "sync" qt_decimal256_mod """ select v1, v2, v1 % v2, v1 % v3 from test_arithmetic_expressions_256_5 ORDER BY id; """ - */ } diff --git a/regression-test/suites/datatype_p0/decimalv3/test_decimal256_cast.groovy b/regression-test/suites/datatype_p0/decimalv3/test_decimal256_cast.groovy new file mode 100644 index 00000000000000..c20c10e288a13c --- /dev/null +++ b/regression-test/suites/datatype_p0/decimalv3/test_decimal256_cast.groovy @@ -0,0 +1,40 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_decimal256_cast") { + sql "set enable_nereids_planner = true;" + sql "set enable_decimal256 = true;" + + qt_decimal256_cast0 """SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ + cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10));""" + qt_decimal256_cast1 """SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ + cast(-999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10));""" + qt_decimal256_cast2 """SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ + cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10));""" + qt_decimal256_cast3 """SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ + cast(-999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10));""" + + qt_decimal256_cast4 """SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ + cast("999999999999999999999999999999999999999999999999999999999999999999.9999999999" as decimalv3(76,10));""" + qt_decimal256_cast5 """SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ + cast("-999999999999999999999999999999999999999999999999999999999999999999.9999999999" as decimalv3(76,10));""" + qt_decimal256_cast6 """SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ + cast("999999999999999999999999999999999999999999999999999999999999999999.9999999999" as decimalv3(76,10));""" + qt_decimal256_cast7 """SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ + cast("-999999999999999999999999999999999999999999999999999999999999999999.9999999999" as decimalv3(76,10));""" + +} \ No newline at end of file diff --git a/regression-test/suites/datatype_p0/decimalv3/test_decimal256_index.groovy b/regression-test/suites/datatype_p0/decimalv3/test_decimal256_index.groovy new file mode 100644 index 00000000000000..8f31323436d63f --- /dev/null +++ b/regression-test/suites/datatype_p0/decimalv3/test_decimal256_index.groovy @@ -0,0 +1,277 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_decimal256_index") { + sql "set enable_nereids_planner = true;" + sql "set enable_decimal256 = true;" + + def delta_time = 100 + def wait_for_latest_op_on_table_finish = { table_name, OpTimeout -> + for(int t = delta_time; t <= OpTimeout; t += delta_time){ + alter_res = sql """SHOW ALTER TABLE COLUMN WHERE TableName = "${table_name}" ORDER BY CreateTime DESC LIMIT 1;""" + alter_res = alter_res.toString() + if(alter_res.contains("FINISHED")) { + sleep(3000) // wait change table state to normal + logger.info(table_name + " latest alter job finished, detail: " + alter_res) + break + } + useTime = t + sleep(delta_time) + } + assertTrue(useTime <= OpTimeout, "wait_for_latest_op_on_table_finish timeout") + } + + // test zonemap index + sql "DROP TABLE IF EXISTS `test_decimal256_zonemap_index`" + sql """ + CREATE TABLE IF NOT EXISTS `test_decimal256_zonemap_index` ( + `k1` decimalv3(76, 9) NULL COMMENT "", + `k2` decimalv3(76, 10) NULL COMMENT "" + ) ENGINE=OLAP + DUPLICATE KEY(`k1`) + DISTRIBUTED BY HASH(`k1`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + streamLoad { + // you can skip db declaration, because a default db has already been + // specified in ${DORIS_HOME}/conf/regression-conf.groovy + // db 'regression_test' + table "test_decimal256_zonemap_index" + + // default label is UUID: + // set 'label' UUID.randomUUID().toString() + + // default column_separator is specify in doris fe config, usually is '\t'. + // this line change to ',' + set 'column_separator', ',' + + // relate to ${DORIS_HOME}/regression-test/data/demo/streamload_input.csv. + // also, you can stream load a http stream, e.g. http://xxx/some.csv + file """test_decimal256_zonemap_index.csv""" + + time 10000 // limit inflight 10s + + // stream load action will check result, include Success status, and NumberTotalRows == NumberLoadedRows + + // if declared a check callback, the default check condition will ignore. + // So you must check all condition + check { result, exception, startTime, endTime -> + if (exception != null) { + throw exception + } + log.info("Stream load result: ${result}".toString()) + def json = parseJson(result) + assertEquals("success", json.Status.toLowerCase()) + assertEquals(4096, json.NumberTotalRows) + assertEquals(json.NumberTotalRows, json.NumberLoadedRows) + assertTrue(json.LoadBytes > 0) + } + } + // RowsStatsFiltered in profile + qt_decimal256_zonemap_0 "select * from test_decimal256_zonemap_index where k2 < 900000000000000000000000000000000000000000000000000000000000000010.9999999999 order by k1, k2;" + + sql "DROP TABLE IF EXISTS `test_decimal256_bitmap_index`" + sql """ + CREATE TABLE IF NOT EXISTS `test_decimal256_bitmap_index` ( + `k1` decimalv3(76, 9) NULL COMMENT "", + `k2` decimalv3(76, 10) NULL COMMENT "", + `k3` decimalv3(76, 11) NULL COMMENT "" + ) ENGINE=OLAP + DUPLICATE KEY(`k1`) + DISTRIBUTED BY HASH(`k1`) BUCKETS 8 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + + sql """insert into test_decimal256_bitmap_index values + (1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (2, 499999999999999999999999999999999999999999999999999999999999999999.9999999999, 49999999999999999999999999999999999999999999999999999999999999999.99999999999), + (3, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (3, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (4, -999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (4, -999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (5, -333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (5, -333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (6, null, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (7, null, 99999999999999999999999999999999999999999999999999999999999999999.99999999999); + """ + sql "sync" + + sql """CREATE INDEX k2_bitmap_index ON test_decimal256_bitmap_index(k2) USING BITMAP;""" + wait_for_latest_op_on_table_finish("test_decimal256_bitmap_index", 3000); + + qt_sql_bitmap_index_select_all """ + select * from test_decimal256_bitmap_index order by 1,2,3; + """ + // profile item RowsBitmapIndexFiltered + qt_sql_eq_1 """ + select * from test_decimal256_bitmap_index where k2 = 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_eq_2 """ + select * from test_decimal256_bitmap_index where k2 = -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_eq_3 """ + select * from test_decimal256_bitmap_index where k2 = -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + + qt_sql_neq_1 """ + select * from test_decimal256_bitmap_index where k2 != 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_neq_2 """ + select * from test_decimal256_bitmap_index where k2 != -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_neq_3 """ + select * from test_decimal256_bitmap_index where k2 != -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + + qt_sql_gt_1 """ + select * from test_decimal256_bitmap_index where k2 > 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_gt_2 """ + select * from test_decimal256_bitmap_index where k2 > -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_gt_3 """ + select * from test_decimal256_bitmap_index where k2 > -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + + qt_sql_ge_1 """ + select * from test_decimal256_bitmap_index where k2 >= 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_ge_2 """ + select * from test_decimal256_bitmap_index where k2 >= -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_ge_3 """ + select * from test_decimal256_bitmap_index where k2 >= -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + + qt_sql_lt_1 """ + select * from test_decimal256_bitmap_index where k2 < 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_lt_2 """ + select * from test_decimal256_bitmap_index where k2 < -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_lt_3 """ + select * from test_decimal256_bitmap_index where k2 < -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + + qt_sql_le_1 """ + select * from test_decimal256_bitmap_index where k2 <= 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_le_2 """ + select * from test_decimal256_bitmap_index where k2 <= -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_le_3 """ + select * from test_decimal256_bitmap_index where k2 <= -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + + // bloom filter index + sql "DROP TABLE IF EXISTS `test_decimal256_bf_index`" + sql """ + CREATE TABLE IF NOT EXISTS `test_decimal256_bf_index` ( + `k1` decimalv3(76, 9) NULL COMMENT "", + `k2` decimalv3(76, 10) NULL COMMENT "", + `k3` decimalv3(76, 11) NULL COMMENT "" + ) ENGINE=OLAP + DUPLICATE KEY(`k1`) + DISTRIBUTED BY HASH(`k1`) BUCKETS 8 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1", + "bloom_filter_columns" = "k2" + ); + """ + + sql """insert into test_decimal256_bf_index values + (1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (2, 499999999999999999999999999999999999999999999999999999999999999999.9999999999, 49999999999999999999999999999999999999999999999999999999999999999.99999999999), + (3, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (3, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (4, -999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (4, -999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (5, -333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (5, -333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (6, null, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (7, null, 99999999999999999999999999999999999999999999999999999999999999999.99999999999); + """ + sql "sync" + + // profile item RowsBloomFilterFiltered + qt_sql_bf_eq_1 """ + select * from test_decimal256_bf_index where k2 = 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_eq_2 """ + select * from test_decimal256_bf_index where k2 = -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_eq_3 """ + select * from test_decimal256_bf_index where k2 = -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + + qt_sql_bf_neq_1 """ + select * from test_decimal256_bf_index where k2 != 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_neq_2 """ + select * from test_decimal256_bf_index where k2 != -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_neq_3 """ + select * from test_decimal256_bf_index where k2 != -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + + qt_sql_bf_gt_1 """ + select * from test_decimal256_bf_index where k2 > 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_gt_2 """ + select * from test_decimal256_bf_index where k2 > -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_gt_3 """ + select * from test_decimal256_bf_index where k2 > -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + + qt_sql_bf_ge_1 """ + select * from test_decimal256_bf_index where k2 >= 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_ge_2 """ + select * from test_decimal256_bf_index where k2 >= -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_ge_3 """ + select * from test_decimal256_bf_index where k2 >= -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + + qt_sql_bf_lt_1 """ + select * from test_decimal256_bf_index where k2 < 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_lt_2 """ + select * from test_decimal256_bf_index where k2 < -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_lt_3 """ + select * from test_decimal256_bf_index where k2 < -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + + qt_sql_bf_le_1 """ + select * from test_decimal256_bf_index where k2 <= 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_le_2 """ + select * from test_decimal256_bf_index where k2 <= -999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + qt_sql_bf_le_3 """ + select * from test_decimal256_bf_index where k2 <= -333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by 1, 2, 3; + """ + +} \ No newline at end of file diff --git a/regression-test/suites/datatype_p0/decimalv3/test_decimal256_load.groovy b/regression-test/suites/datatype_p0/decimalv3/test_decimal256_load.groovy new file mode 100644 index 00000000000000..d2f141d902f609 --- /dev/null +++ b/regression-test/suites/datatype_p0/decimalv3/test_decimal256_load.groovy @@ -0,0 +1,345 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_decimal256_load") { + sql "set enable_nereids_planner = true;" + sql "set enable_decimal256 = true;" + + // test insert + sql "DROP TABLE IF EXISTS `test_decimal256_insert`" + sql """ + CREATE TABLE IF NOT EXISTS `test_decimal256_insert` ( + `k1` decimalv3(76, 9) NULL COMMENT "", + `k2` decimalv3(76, 10) NULL COMMENT "", + `k3` decimalv3(76, 11) NULL COMMENT "" + ) ENGINE=OLAP + DUPLICATE KEY(`k1`) + DISTRIBUTED BY HASH(`k1`) BUCKETS 8 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + sql """ + insert into test_decimal256_insert values + (2, 499999999999999999999999999999999999999999999999999999999999999999.9999999999, 49999999999999999999999999999999999999999999999999999999999999999.99999999999), + (1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (4, -999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (3, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (4, -999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (3, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (5, -333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (5, -333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (6, null, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (7, null, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (0, 0, 0), + (99999999999999999999999999999.999999999, 1, 1), + (-99999999999999999999999999999.999999999, 1, 1), + (9999999999999999999999999999999999999999999999999999999999999999999.999999999, 1, 1), + (-9999999999999999999999999999999999999999999999999999999999999999999.999999999, 1, 1), + (4999999999999999999999999999999999999999999999999999999999999999999.999999999, 1, 1), + (-4999999999999999999999999999999999999999999999999999999999999999999.999999999, 1, 1), + (null, null, null); + """ + sql "sync" + qt_decimal256_insert_select_all0 "select * from test_decimal256_insert order by 1,2,3;" + + // test stream load + sql "DROP TABLE IF EXISTS `test_decimal256_load`" + sql """ + CREATE TABLE IF NOT EXISTS `test_decimal256_load` ( + `k1` decimalv3(76, 9) NULL COMMENT "", + `k2` decimalv3(76, 10) NULL default '999999999999999999999999999999999999999999999999999999999999999999.9999999999' COMMENT "", + `k3` decimalv3(76, 11) NULL COMMENT "" + ) ENGINE=OLAP + DUPLICATE KEY(`k1`) + DISTRIBUTED BY HASH(`k1`) BUCKETS 8 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + streamLoad { + // you can skip db declaration, because a default db has already been + // specified in ${DORIS_HOME}/conf/regression-conf.groovy + // db 'regression_test' + table "test_decimal256_load" + + // default label is UUID: + // set 'label' UUID.randomUUID().toString() + + // default column_separator is specify in doris fe config, usually is '\t'. + // this line change to ',' + set 'column_separator', ',' + + // relate to ${DORIS_HOME}/regression-test/data/demo/streamload_input.csv. + // also, you can stream load a http stream, e.g. http://xxx/some.csv + file """test_decimal256_load.csv""" + + time 10000 // limit inflight 10s + + // stream load action will check result, include Success status, and NumberTotalRows == NumberLoadedRows + + // if declared a check callback, the default check condition will ignore. + // So you must check all condition + check { result, exception, startTime, endTime -> + if (exception != null) { + throw exception + } + log.info("Stream load result: ${result}".toString()) + def json = parseJson(result) + assertEquals("success", json.Status.toLowerCase()) + assertEquals(19, json.NumberTotalRows) + assertEquals(json.NumberTotalRows, json.NumberLoadedRows) + assertTrue(json.LoadBytes > 0) + } + } + qt_select "select * from test_decimal256_load order by 1,2,3;" + + qt_select_key_eq0 """ + select * from test_decimal256_load where k1 = 9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_eq1 """ + select * from test_decimal256_load where k1 = 4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_eq2 """ + select * from test_decimal256_load where k1 = -4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_eq3 """ + select * from test_decimal256_load where k1 = -9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_eq4 """ + select * from test_decimal256_load where k1 = 0 order by 1, 2, 3; + """ + qt_select_key_eq5 """ + select * from test_decimal256_load where k1 = null order by 1, 2, 3; + """ + + qt_select_key_neq0 """ + select * from test_decimal256_load where k1 != 9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_neq1 """ + select * from test_decimal256_load where k1 != 4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_neq2 """ + select * from test_decimal256_load where k1 != -4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_neq3 """ + select * from test_decimal256_load where k1 != -9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_neq4 """ + select * from test_decimal256_load where k1 != 0 order by 1, 2, 3; + """ + qt_select_key_neq5 """ + select * from test_decimal256_load where k1 != null order by 1, 2, 3; + """ + + qt_select_key_gt0 """ + select * from test_decimal256_load where k1 > 9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_gt1 """ + select * from test_decimal256_load where k1 > 4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_gt2 """ + select * from test_decimal256_load where k1 > -4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_gt3 """ + select * from test_decimal256_load where k1 > -9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_gt4 """ + select * from test_decimal256_load where k1 > 0 order by 1, 2, 3; + """ + qt_select_key_gt5 """ + select * from test_decimal256_load where k1 > null order by 1, 2, 3; + """ + + qt_select_key_ge0 """ + select * from test_decimal256_load where k1 >= 9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_ge1 """ + select * from test_decimal256_load where k1 >= 4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_ge2 """ + select * from test_decimal256_load where k1 >= -4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_ge3 """ + select * from test_decimal256_load where k1 >= -9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_ge4 """ + select * from test_decimal256_load where k1 >= 0 order by 1, 2, 3; + """ + qt_select_key_ge5 """ + select * from test_decimal256_load where k1 >= null order by 1, 2, 3; + """ + + qt_select_key_lt0 """ + select * from test_decimal256_load where k1 < 9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_lt1 """ + select * from test_decimal256_load where k1 < 4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_lt2 """ + select * from test_decimal256_load where k1 < -4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_lt3 """ + select * from test_decimal256_load where k1 < -9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_lt4 """ + select * from test_decimal256_load where k1 < 0 order by 1, 2, 3; + """ + qt_select_key_lt5 """ + select * from test_decimal256_load where k1 < null order by 1, 2, 3; + """ + + qt_select_key_le0 """ + select * from test_decimal256_load where k1 <= 9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_le1 """ + select * from test_decimal256_load where k1 <= 4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_le2 """ + select * from test_decimal256_load where k1 <= -4999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_le3 """ + select * from test_decimal256_load where k1 <= -9999999999999999999999999999999999999999999999999999999999999999999.999999999 order by 1, 2, 3; + """ + qt_select_key_le4 """ + select * from test_decimal256_load where k1 <= 0 order by 1, 2, 3; + """ + qt_select_key_le5 """ + select * from test_decimal256_load where k1 <= null order by 1, 2, 3; + """ + + qt_select_key_in0 """ + select * from test_decimal256_load where k1 in (9999999999999999999999999999999999999999999999999999999999999999999.999999999) order by 1, 2, 3; + """ + qt_select_key_in1 """ + select * from test_decimal256_load where k1 in (-9999999999999999999999999999999999999999999999999999999999999999999.999999999) order by 1, 2, 3; + """ + qt_select_key_in2 """ + select * from test_decimal256_load where k1 in(4999999999999999999999999999999999999999999999999999999999999999999.999999999) order by 1, 2, 3; + """ + qt_select_key_in3 """ + select * from test_decimal256_load where k1 in(-4999999999999999999999999999999999999999999999999999999999999999999.999999999) order by 1, 2, 3; + """ + qt_select_key_in4 """ + select * from test_decimal256_load where k1 in(0) order by 1, 2, 3; + """ + qt_select_key_in5 """ + select * from test_decimal256_load where k1 in ( + 9999999999999999999999999999999999999999999999999999999999999999999.999999999, + -9999999999999999999999999999999999999999999999999999999999999999999.999999999, + 4999999999999999999999999999999999999999999999999999999999999999999.999999999, + -4999999999999999999999999999999999999999999999999999999999999999999.999999999, + 0 + ) order by 1, 2, 3; + """ + qt_select_key_in6 """ + select * from test_decimal256_load where k1 in(null) order by 1, 2, 3; + """ + qt_select_key_in7 """ + select * from test_decimal256_load where k1 in(0, null) order by 1, 2, 3; + """ + + qt_select_key_notin0 """ + select * from test_decimal256_load where k1 not in (9999999999999999999999999999999999999999999999999999999999999999999.999999999) order by 1, 2, 3; + """ + qt_select_key_notin1 """ + select * from test_decimal256_load where k1 not in (-9999999999999999999999999999999999999999999999999999999999999999999.999999999) order by 1, 2, 3; + """ + qt_select_key_notin2 """ + select * from test_decimal256_load where k1 not in(4999999999999999999999999999999999999999999999999999999999999999999.999999999) order by 1, 2, 3; + """ + qt_select_key_notin3 """ + select * from test_decimal256_load where k1 not in(-4999999999999999999999999999999999999999999999999999999999999999999.999999999) order by 1, 2, 3; + """ + qt_select_key_notin4 """ + select * from test_decimal256_load where k1 not in(0) order by 1, 2, 3; + """ + qt_select_key_notin5 """ + select * from test_decimal256_load where k1 not in ( + 9999999999999999999999999999999999999999999999999999999999999999999.999999999, + -9999999999999999999999999999999999999999999999999999999999999999999.999999999, + 4999999999999999999999999999999999999999999999999999999999999999999.999999999, + -4999999999999999999999999999999999999999999999999999999999999999999.999999999, + 0 + ) order by 1, 2, 3; + """ + qt_select_key_notin6 """ + select * from test_decimal256_load where k1 not in(null) order by 1, 2, 3; + """ + qt_select_key_notin7 """ + select * from test_decimal256_load where k1 not in(0, null) order by 1, 2, 3; + """ + + qt_select_key_is_null """ + select * from test_decimal256_load where k1 is null order by 1, 2, 3; + """ + qt_select_key_is_not_null """ + select * from test_decimal256_load where k1 is not null order by 1, 2, 3; + """ + + qt_sql_eq_1 """ + select * from test_decimal256_load where k2 = 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + + qt_sql_neq_1 """ + select * from test_decimal256_load where k2 != 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + + qt_sql_gt_1 """ + select * from test_decimal256_load where k2 > 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + + qt_sql_ge_1 """ + select * from test_decimal256_load where k2 >= 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + + qt_sql_lt_1 """ + select * from test_decimal256_load where k2 < 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + + qt_sql_le_1 """ + select * from test_decimal256_load where k2 <= 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + + sql "DROP TABLE IF EXISTS `test_decimal256_load2`" + sql """ + CREATE TABLE IF NOT EXISTS `test_decimal256_load2` ( + `k1` decimalv3(76, 9) NULL COMMENT "", + `k2` decimalv3(76, 10) NULL COMMENT "", + `k3` decimalv3(76, 11) NULL COMMENT "" + ) ENGINE=OLAP + DUPLICATE KEY(`k1`) + DISTRIBUTED BY HASH(`k1`) BUCKETS 8 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + sql "insert into test_decimal256_load2 select * from test_decimal256_load;" + sql "sync" + qt_select_2 "select * from test_decimal256_load2 order by 1,2,3;" + qt_sql_insert_select_eq_1 """ + select * from test_decimal256_load2 where k2 = 999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by 1, 2, 3; + """ + + // test default value + sql "insert into test_decimal256_load(k1,k3) values (0, 0), (99999, 99999), (-99999, -99999);" + sql "sync" + qt_sql_select_insert_default0 "select * from test_decimal256_load order by k1,k2,k3;" + qt_sql_select_insert_default1 "select * from test_decimal256_load where k1 = 99999;" + qt_sql_select_insert_default2 "select * from test_decimal256_load where k1 = -99999;" +} \ No newline at end of file diff --git a/regression-test/suites/datatype_p0/decimalv3/test_decimal256_outfile_csv.groovy b/regression-test/suites/datatype_p0/decimalv3/test_decimal256_outfile_csv.groovy new file mode 100644 index 00000000000000..54bbb5ca3fa330 --- /dev/null +++ b/regression-test/suites/datatype_p0/decimalv3/test_decimal256_outfile_csv.groovy @@ -0,0 +1,135 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import org.codehaus.groovy.runtime.IOGroovyMethods + +import java.nio.charset.StandardCharsets +import java.nio.file.Files +import java.nio.file.Paths + +suite("test_decimal256_outfile_csv") { + StringBuilder strBuilder = new StringBuilder() + strBuilder.append("curl --location-trusted -u " + context.config.jdbcUser + ":" + context.config.jdbcPassword) + strBuilder.append(" http://" + context.config.feHttpAddress + "/rest/v1/config/fe") + + String command = strBuilder.toString() + def process = command.toString().execute() + def code = process.waitFor() + def err = IOGroovyMethods.getText(new BufferedReader(new InputStreamReader(process.getErrorStream()))); + def out = process.getText() + logger.info("Request FE Config: code=" + code + ", out=" + out + ", err=" + err) + assertEquals(code, 0) + def response = parseJson(out.trim()) + assertEquals(response.code, 0) + assertEquals(response.msg, "success") + def configJson = response.data.rows + boolean enableOutfileToLocal = false + for (Object conf: configJson) { + assert conf instanceof Map + if (((Map) conf).get("Name").toLowerCase() == "enable_outfile_to_local") { + enableOutfileToLocal = ((Map) conf).get("Value").toLowerCase() == "true" + } + } + if (!enableOutfileToLocal) { + logger.warn("Please set enable_outfile_to_local to true to run test_outfile") + return + } + + sql "set enable_nereids_planner = true;" + sql "set enable_decimal256 = true;" + + sql "DROP TABLE IF EXISTS `test_decimal256_outfile_csv`" + sql """ + CREATE TABLE IF NOT EXISTS `test_decimal256_outfile_csv` ( + `k1` decimalv3(76, 9) NULL COMMENT "", + `k2` decimalv3(76, 10) NULL default '999999999999999999999999999999999999999999999999999999999999999999.9999999999' COMMENT "", + `k3` decimalv3(76, 11) NULL COMMENT "" + ) ENGINE=OLAP + DUPLICATE KEY(`k1`) + DISTRIBUTED BY HASH(`k1`) BUCKETS 8 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + streamLoad { + // you can skip db declaration, because a default db has already been + // specified in ${DORIS_HOME}/conf/regression-conf.groovy + // db 'regression_test' + table "test_decimal256_outfile_csv" + + // default label is UUID: + // set 'label' UUID.randomUUID().toString() + + // default column_separator is specify in doris fe config, usually is '\t'. + // this line change to ',' + set 'column_separator', ',' + + // relate to ${DORIS_HOME}/regression-test/data/demo/streamload_input.csv. + // also, you can stream load a http stream, e.g. http://xxx/some.csv + file """test_decimal256_load.csv""" + + time 10000 // limit inflight 10s + + // stream load action will check result, include Success status, and NumberTotalRows == NumberLoadedRows + + // if declared a check callback, the default check condition will ignore. + // So you must check all condition + check { result, exception, startTime, endTime -> + if (exception != null) { + throw exception + } + log.info("Stream load result: ${result}".toString()) + def json = parseJson(result) + assertEquals("success", json.Status.toLowerCase()) + assertEquals(19, json.NumberTotalRows) + assertEquals(json.NumberTotalRows, json.NumberLoadedRows) + assertTrue(json.LoadBytes > 0) + } + } + sql "sync" + qt_sql_select_all """ + SELECT * FROM test_decimal256_outfile_csv t order by 1,2,3; + """ + + def uuid = UUID.randomUUID().toString() + def outFilePath = """/tmp/test_decimal256_outfile_csv_${uuid}""" + try { + logger.info("outfile: " + outFilePath) + // check outfile + File path = new File(outFilePath) + if (!path.exists()) { + assert path.mkdirs() + } else { + throw new IllegalStateException("""${outFilePath} already exists! """) + } + sql """ + SELECT * FROM test_decimal256_outfile_csv t order by 1,2,3 INTO OUTFILE "file://${outFilePath}/" properties("column_separator" = ","); + """ + File[] files = path.listFiles() + assert files.length == 1 + List outLines = Files.readAllLines(Paths.get(files[0].getAbsolutePath()), StandardCharsets.UTF_8); + assert outLines.size() == 19 + } finally { + File path = new File(outFilePath) + if (path.exists()) { + for (File f: path.listFiles()) { + f.delete(); + } + path.delete(); + } + } +} \ No newline at end of file diff --git a/regression-test/suites/datatype_p0/decimalv3/test_decimal256_predicate.groovy b/regression-test/suites/datatype_p0/decimalv3/test_decimal256_predicate.groovy new file mode 100644 index 00000000000000..9664d50068b2bf --- /dev/null +++ b/regression-test/suites/datatype_p0/decimalv3/test_decimal256_predicate.groovy @@ -0,0 +1,128 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_decimal256_predicate") { + sql "set enable_nereids_planner = true;" + sql "set enable_decimal256 = true;" + + qt_select256_1 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) > cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_2 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10)) > cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_3 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) >= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_4 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999997 as decimalv3(76,10)) >= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + + qt_select256_5 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10)) < cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10))" + qt_select256_6 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) < cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_7 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10)) <= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_8 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) <= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + + qt_select256_9 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) = cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10))" + qt_select256_10 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) = cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + + qt_select256_11 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) != cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_12 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) != cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10))" + + qt_select256_fold_const_by_be1 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) > cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_fold_const_by_be2 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10)) > cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_fold_const_by_be3 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) >= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_fold_const_by_be4 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999997 as decimalv3(76,10)) >= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + + qt_select256_fold_const_by_be5 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10)) < cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10))" + qt_select256_fold_const_by_be6 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) < cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_fold_const_by_be7 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10)) <= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_fold_const_by_be8 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) <= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + + qt_select256_fold_const_by_be9 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) = cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10))" + qt_select256_fold_const_by_be10 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) = cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + + qt_select256_fold_const_by_be11 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) != cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" + qt_select256_fold_const_by_be12 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = true) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) != cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10))" + + + sql "DROP TABLE IF EXISTS `test_predicate_128_1`"; + sql """ + CREATE TABLE IF NOT EXISTS `test_predicate_128_1` ( + `k1` decimalv3(38, 6) NULL COMMENT "", + `k2` decimalv3(38, 6) NULL COMMENT "", + `k3` decimalv3(38, 6) NULL COMMENT "" + ) ENGINE=OLAP + COMMENT "OLAP" + DISTRIBUTED BY HASH(`k1`, `k2`, `k3`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + sql """insert into test_predicate_128_1 values + (1, 99999999999999999999999999999999.999999, 99999999999999999999999999999999.999999), + (2, 49999999999999999999999999999999.999999, 49999999999999999999999999999999.999999), + (3, 33333333333333333333333333333333.333333, 33333333333333333333333333333333.333333), + (4.444444, 2.222222, 3.333333);""" + sql "sync" + qt_decimal256_select_all "select * from test_predicate_128_1 order by k1, k2;" + qt_decimal256_predicate_0 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) > (cast(33333333333333333333333333333333.333333 as decimalv3(76,7))) order by k1, k2;" + qt_decimal256_predicate_1 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) >= (cast(999999999999999999999999999999990.999999 as decimalv3(76,6)) / 10) order by k1, k2;" + + qt_decimal256_predicate_2 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) < (cast(49999999999999999999999999999999.999999 as decimalv3(76,7))) order by k1, k2;" + qt_decimal256_predicate_3 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) <= (cast(33333333333333333333333333333333.333333 as decimalv3(76,7))) order by k1, k2;" + + qt_decimal256_predicate_4 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) = (cast(99999999999999999999999999999999.999999 as decimalv3(76,7))) order by k1, k2;" + qt_decimal256_predicate_5 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) != (cast(99999999999999999999999999999999.999999 as decimalv3(76,7))) order by k1, k2;" + + sql "DROP TABLE IF EXISTS `test_predicate_256_1`" + sql """ + CREATE TABLE IF NOT EXISTS `test_predicate_256_1` ( + `k1` decimalv3(76, 9) NULL COMMENT "", + `k2` decimalv3(76, 10) NULL COMMENT "", + `k3` decimalv3(76, 11) NULL COMMENT "" + ) ENGINE=OLAP + DUPLICATE KEY(`k1`) + DISTRIBUTED BY HASH(`k1`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + + sql """insert into test_predicate_256_1 values + (1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (1, 999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (2, 499999999999999999999999999999999999999999999999999999999999999999.9999999999, 49999999999999999999999999999999999999999999999999999999999999999.99999999999), + (3, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (3, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (4, -999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (4, -999999999999999999999999999999999999999999999999999999999999999999.9999999999, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (5, -333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (5, -333333333333333333333333333333333333333333333333333333333333333333.3333333333, 33333333333333333333333333333333333333333333333333333333333333333.33333333333), + (6, null, 99999999999999999999999999999999999999999999999999999999999999999.99999999999), + (7, null, 99999999999999999999999999999999999999999999999999999999999999999.99999999999); + """ + sql "sync" + qt_decimal256_select_all2 "select * from test_predicate_256_1 order by k1, k2;" + qt_decimal256_predicate_6 "select * from test_predicate_256_1 where k2 > 333333333333333333333333333333333333333333333333333333333333333333.3333333333 order by k1, k2;" + qt_decimal256_predicate_7 "select * from test_predicate_256_1 where k2 >= 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by k1, k2;" + + qt_decimal256_predicate_8 "select * from test_predicate_256_1 where k2 < 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by k1, k2;" + qt_decimal256_predicate_9 "select * from test_predicate_256_1 where k2 <= 499999999999999999999999999999999999999999999999999999999999999999.9999999999 order by k1, k2;" + + qt_decimal256_predicate_10 "select * from test_predicate_256_1 where k2 = 999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by k1, k2;" + qt_decimal256_predicate_11 "select * from test_predicate_256_1 where k2 != 999999999999999999999999999999999999999999999999999999999999999999.9999999999 order by k1, k2;" + + qt_decimal256_predicate_12 "select * from test_predicate_256_1 where k2 in(1, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 999999999999999999999999999999999999999999999999999999999999999999.9999999999) order by k1, k2;" + qt_decimal256_predicate_13 "select * from test_predicate_256_1 where k2 not in(2, 333333333333333333333333333333333333333333333333333333333333333333.3333333333, 999999999999999999999999999999999999999999999999999999999999999999.9999999999) order by k1, k2;" + + // test delete + sql "delete from test_predicate_256_1 where k2 >= 499999999999999999999999999999999999999999999999999999999999999999.9999999999;" + qt_decimal256_predicate_14 "select * from test_predicate_256_1 order by k1, k2;" +} \ No newline at end of file diff --git a/regression-test/suites/datatype_p0/decimalv3/test_predicate.groovy b/regression-test/suites/datatype_p0/decimalv3/test_predicate.groovy index a8e12dcb4e62af..65555c9217a32e 100644 --- a/regression-test/suites/datatype_p0/decimalv3/test_predicate.groovy +++ b/regression-test/suites/datatype_p0/decimalv3/test_predicate.groovy @@ -39,6 +39,7 @@ suite("test_predicate") { (1.2,1.2,1.3), (1.5,1.2,1.3) """ + sql "sync" qt_select1 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ CAST((CASE WHEN (TRUE IS NOT NULL) THEN '1.2' ELSE '1.2' END) AS FLOAT) = CAST(1.2 AS decimal(2,1))" qt_select2 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ 1 FROM ${table1} WHERE CAST((CASE WHEN (TRUE IS NOT NULL) THEN '1.2' ELSE '1.2' END) AS FLOAT) = CAST(1.2 AS decimal(2,1));" @@ -51,49 +52,4 @@ suite("test_predicate") { qt_select5 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ 1 FROM ${table1} WHERE CAST((CASE WHEN (TRUE IS NOT NULL) THEN '1.2' ELSE '1.2' END) AS FLOAT) = CAST(1.2 AS decimal(76,1));" qt_select6 "SELECT * FROM ${table1} WHERE k1 != cast(1.1 as decimalv3(76, 1)) ORDER BY k1" sql "drop table if exists ${table1}" - - qt_select256_1 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) > cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" - qt_select256_2 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10)) > cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" - qt_select256_3 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) >= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" - qt_select256_4 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999997 as decimalv3(76,10)) >= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" - - qt_select256_5 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10)) < cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10))" - qt_select256_6 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) < cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" - qt_select256_7 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10)) <= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" - qt_select256_8 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) <= cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" - - qt_select256_9 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) = cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10))" - qt_select256_10 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) = cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" - - qt_select256_11 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) != cast(999999999999999999999999999999999999999999999999999999999999999999.9999999998 as decimalv3(76,10))" - qt_select256_12 "SELECT /*+ SET_VAR(enable_fold_constant_by_be = false) */ cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10)) != cast(999999999999999999999999999999999999999999999999999999999999999999.9999999999 as decimalv3(76,10))" - - - sql "DROP TABLE IF EXISTS `test_predicate_128_1`"; - sql """ - CREATE TABLE IF NOT EXISTS `test_predicate_128_1` ( - `k1` decimalv3(38, 6) NULL COMMENT "", - `k2` decimalv3(38, 6) NULL COMMENT "", - `k3` decimalv3(38, 6) NULL COMMENT "" - ) ENGINE=OLAP - COMMENT "OLAP" - DISTRIBUTED BY HASH(`k1`, `k2`, `k3`) BUCKETS 8 - PROPERTIES ( - "replication_allocation" = "tag.location.default: 1" - ); - """ - sql """insert into test_predicate_128_1 values(1, 99999999999999999999999999999999.999999, 99999999999999999999999999999999.999999), - (2, 49999999999999999999999999999999.999999, 49999999999999999999999999999999.999999), - (3, 33333333333333333333333333333333.333333, 33333333333333333333333333333333.333333), - (4.444444, 2.222222, 3.333333);""" - qt_decimal256_select_all "select * from test_predicate_128_1 order by k1, k2;" - qt_decimal256_predicate_0 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) > (cast(33333333333333333333333333333333.333333 as decimalv3(76,7))) order by k1, k2;" - qt_decimal256_predicate_1 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) >= (cast(999999999999999999999999999999990.999999 as decimalv3(76,6)) / 10)order by k1, k2;" - - qt_decimal256_predicate_2 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) < (cast(49999999999999999999999999999999.999999 as decimalv3(76,7))) order by k1, k2;" - qt_decimal256_predicate_3 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) <= (cast(33333333333333333333333333333333.333333 as decimalv3(76,7))) order by k1, k2;" - - qt_decimal256_predicate_4 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) = (cast(99999999999999999999999999999999.999999 as decimalv3(76,7))) order by k1, k2;" - qt_decimal256_predicate_5 "select * from test_predicate_128_1 where cast(k2 as decimalv3(76, 6)) != (cast(99999999999999999999999999999999.999999 as decimalv3(76,7))) order by k1, k2;" - } From f018b00646ef5c9734ed16808eb0cc2dd25856db Mon Sep 17 00:00:00 2001 From: Dongyang Li Date: Wed, 8 Nov 2023 15:32:02 +0800 Subject: [PATCH 45/88] [ci](perf) add new pipeline of tpch-sf100 (#26334) * [ci](perf) add new pipeline of tpch-sf100 Co-authored-by: stephen --- be/src/common/config.h | 2 +- .../pipeline/common/doris-utils.sh | 259 ++++++++++++++++++ .../pipeline/common/github-utils.sh | 65 +++++ regression-test/pipeline/common/oss-utils.sh | 105 +++++++ .../pipeline/tpch/tpch-sf100/clean.sh | 40 +++ .../pipeline/tpch/tpch-sf100/conf/be.conf | 85 ++++++ .../tpch/tpch-sf100/conf/external.json | 26 ++ .../pipeline/tpch/tpch-sf100/conf/fe.conf | 78 ++++++ .../tpch/tpch-sf100/conf/odbcinst.ini | 43 +++ .../tpch-sf100/conf/regression-conf.groovy | 111 ++++++++ .../pipeline/tpch/tpch-sf100/deploy.sh | 132 +++++++++ .../pipeline/tpch/tpch-sf100/prepare.sh | 71 +++++ .../pipeline/tpch/tpch-sf100/run.sh | 143 ++++++++++ tools/tpch-tools/bin/create-tpch-tables.sh | 2 +- tools/tpch-tools/bin/load-tpch-data.sh | 16 +- tools/tpch-tools/bin/run-tpch-queries.sh | 1 + 16 files changed, 1169 insertions(+), 10 deletions(-) create mode 100644 regression-test/pipeline/common/doris-utils.sh create mode 100644 regression-test/pipeline/common/github-utils.sh create mode 100644 regression-test/pipeline/common/oss-utils.sh create mode 100644 regression-test/pipeline/tpch/tpch-sf100/clean.sh create mode 100644 regression-test/pipeline/tpch/tpch-sf100/conf/be.conf create mode 100644 regression-test/pipeline/tpch/tpch-sf100/conf/external.json create mode 100644 regression-test/pipeline/tpch/tpch-sf100/conf/fe.conf create mode 100644 regression-test/pipeline/tpch/tpch-sf100/conf/odbcinst.ini create mode 100644 regression-test/pipeline/tpch/tpch-sf100/conf/regression-conf.groovy create mode 100644 regression-test/pipeline/tpch/tpch-sf100/deploy.sh create mode 100644 regression-test/pipeline/tpch/tpch-sf100/prepare.sh create mode 100644 regression-test/pipeline/tpch/tpch-sf100/run.sh diff --git a/be/src/common/config.h b/be/src/common/config.h index b6f8d2c2fb20bb..493f9342aa7758 100644 --- a/be/src/common/config.h +++ b/be/src/common/config.h @@ -110,7 +110,7 @@ DECLARE_Int32(brpc_num_threads); // If no ip match this rule, will choose one randomly. DECLARE_String(priority_networks); -// performance moderate or or compact, only tcmalloc compile +// performance moderate or compact, only tcmalloc compile DECLARE_String(memory_mode); // process memory limit specified as number of bytes diff --git a/regression-test/pipeline/common/doris-utils.sh b/regression-test/pipeline/common/doris-utils.sh new file mode 100644 index 00000000000000..dddc1fc5f5d22c --- /dev/null +++ b/regression-test/pipeline/common/doris-utils.sh @@ -0,0 +1,259 @@ +#!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +function get_doris_conf_value() { + local conf_file="$1" + local conf_key="$2" + if [[ -z "${conf_key}" ]]; then return 1; fi + + local conf_value + if line="$(grep "^${conf_key}" "${conf_file}")"; then + conf_value="${line#*=}" #取第一个等号后面的子串为value + conf_value="$(echo "${conf_value}" | xargs)" #去掉前导和尾随空格 + echo "${conf_value}" + return 0 + else + echo "ERROR: can not find ${conf_key} in ${conf_file}" + return 1 + fi +} + +function set_doris_conf_value() { + local conf_file="$1" + local conf_key="$2" + local conf_value="$3" + if [[ -z "${conf_value}" ]]; then return 1; fi + + local origin_conf_value + if origin_conf_value="$(get_conf_value "${conf_file}" "${conf_key}")"; then + echo "origin_conf_value is ${origin_conf_value}" + sed -i "/^${conf_key}/d" "${conf_file}" + fi + echo "${conf_key}=${conf_value}" | tee -a "${conf_file}" +} + +# set -x +# get_doris_conf_value "$1" "$2" +# set_doris_conf_value "$1" "$2" "$3" + +function start_doris_fe() { + if [[ ! -d "${DORIS_HOME:-}" ]]; then return 1; fi + if ! java -version >/dev/null; then sudo apt install openjdk-8-jdk -y >/dev/null; fi + JAVA_HOME="$(find /usr/lib/jvm -maxdepth 1 -type d -name 'java-8-*' | sed -n '1p')" + export JAVA_HOME + "${DORIS_HOME}"/fe/bin/start_fe.sh --daemon + + if ! mysql --version >/dev/null; then sudo apt install -y mysql-client; fi + query_port=$(get_doris_conf_value "${DORIS_HOME}"/fe/conf/fe.conf query_port) + cl="mysql -h127.0.0.1 -P${query_port} -uroot " + local i=1 + while [[ $((i++)) -lt 60 ]]; do + fe_version=$(${cl} -e 'show frontends\G' 2>/dev/null | grep -i version | cut -d: -f2) + if [[ -n "${fe_version}" ]] && [[ "${fe_version}" != "NULL" ]]; then + echo "INFO: doris fe started, fe version: ${fe_version}" && return 0 + else + echo "${i}/60, Wait for Frontend ready, sleep 2 seconds ..." && sleep 2 + fi + done + if [[ ${i} -ge 60 ]]; then echo "ERROR: Start Doris Frontend Failed after 2 mins wait..." && return 1; fi + +} + +function start_doris_be() { + if [[ ! -d "${DORIS_HOME:-}" ]]; then return 1; fi + if ! java -version >/dev/null; then sudo apt install openjdk-8-jdk -y >/dev/null; fi + JAVA_HOME="$(find /usr/lib/jvm -maxdepth 1 -type d -name 'java-8-*' | sed -n '1p')" + export JAVA_HOME + sysctl -w vm.max_map_count=2000000 && + ulimit -n 200000 && + ulimit -c unlimited && + swapoff -a && + "${DORIS_HOME}"/be/bin/start_be.sh --daemon + + sleep 2 + local i=1 + while [[ $((i++)) -lt 5 ]]; do + if ! pgrep -fia doris_be >/dev/null; then + echo "ERROR: start doris be failed." && return 1 + else + sleep 2 + fi + done + if [[ ${i} -ge 5 ]]; then + echo "INFO: doris be started, be version: $("${DORIS_HOME}"/be/lib/doris_be --version)" + fi +} + +function add_doris_be_to_fe() { + if [[ ! -d "${DORIS_HOME:-}" ]]; then return 1; fi + if ! mysql --version >/dev/null; then sudo apt install -y mysql-client; fi + query_port=$(get_doris_conf_value "${DORIS_HOME}"/fe/conf/fe.conf query_port) + heartbeat_service_port=$(get_doris_conf_value "${DORIS_HOME}"/be/conf/be.conf heartbeat_service_port) + cl="mysql -h127.0.0.1 -P${query_port} -uroot " + if ${cl} -e "ALTER SYSTEM ADD BACKEND '127.0.0.1:${heartbeat_service_port}';"; then echo; else echo; fi + + i=1 + while [[ $((i++)) -lt 60 ]]; do + if be_ready_count=$(${cl} -e 'show backends\G' | grep -c 'Alive: true') && + [[ ${be_ready_count} -eq 1 ]]; then + echo -e "INFO: add doris be success, be version: \n$(${cl} -e 'show backends\G' | grep 'Version')" && break + else + echo 'Wait for Backends ready, sleep 2 seconds ...' && sleep 2 + fi + done + if [[ ${i} -eq 60 ]]; then echo "ERROR: Add Doris Backend Failed after 2 mins wait..." && return 1; fi +} + +function stop_doris() { + if "${DORIS_HOME}"/fe/bin/stop_fe.sh && + "${DORIS_HOME}"/be/bin/stop_be.sh; then + echo "INFO: normally stoped doris" + else + pgrep -fi doris | xargs kill -9 + echo "WARNING: force stoped doris" + fi +} + +function check_tpch_table_rows() { + if [[ ! -d "${DORIS_HOME:-}" ]]; then return 1; fi + db_name="$1" + scale_factor="$2" + if [[ -z "${scale_factor}" ]]; then return 1; fi + + query_port=$(get_doris_conf_value "${DORIS_HOME}"/fe/conf/fe.conf query_port) + cl="mysql -h127.0.0.1 -P${query_port} -uroot " + declare -A table_rows + if [[ "${scale_factor}" == "100" ]]; then + table_rows=(['region']=5 ['nation']=25 ['supplier']=1000000 ['customer']=15000000 ['part']=20000000 ['partsupp']=80000000 ['orders']=150000000 ['lineitem']=600037902) + else + table_rows=(['region']=5 ['nation']=25 ['supplier']=10000 ['customer']=150000 ['part']=200000 ['partsupp']=800000 ['orders']=1500000 ['lineitem']=6001215) + fi + for table in ${!table_rows[*]}; do + rows_actual=$(${cl} -D"${db_name}" -e"SELECT count(*) FROM ${table}" | sed -n '2p') + rows_expect=${table_rows[${table}]} + if [[ ${rows_actual} -ne ${rows_expect} ]]; then + echo "WARNING: ${table} actual rows: ${rows_actual}, expect rows: ${rows_expect}" && return 1 + fi + done +} + +get_session_variable() { + if [[ ! -d "${DORIS_HOME:-}" ]]; then return 1; fi + usage=" + usage: + get_session_variable SESSION_VARIABLE + return the value of the SESSION_VARIABLE + " + if [[ -z "$1" ]]; then echo "${usage}" && return 1; else sv="$1"; fi + + query_port=$(get_doris_conf_value "${DORIS_HOME}"/fe/conf/fe.conf query_port) + cl="mysql -h127.0.0.1 -P${query_port} -uroot " + + if ret=$(${cl} -e"show variables like '${sv}'\G" | grep " Value: "); then + echo "${ret/*Value: /}" + else + return 1 + fi +} + +set_session_variables_from_file() { + usage=" + usage: + set_session_variables_from_file FILE + FILE content lile ' + session_variable_key session_variable_value + ... + ' + " + if [[ ! -d "${DORIS_HOME:-}" ]]; then return 1; fi + if [[ -z "$1" ]]; then echo "${usage}" && return 1; else sv_file="$1"; fi + + query_port=$(get_doris_conf_value "${DORIS_HOME}"/fe/conf/fe.conf query_port) + cl="mysql -h127.0.0.1 -P${query_port} -uroot " + + ret=0 + while read -r sv; do + if [[ "${sv}" == "#"* ]]; then continue; fi + k=$(echo "${sv}" | awk '{print $1}') + v=$(echo "${sv}" | awk '{print $2}' | tr '[:upper:]' '[:lower:]') + if ${cl} -e"set global ${k}=${v};"; then + if [[ "$(get_session_variable "${k}" | tr '[:upper:]' '[:lower:]')" == "${v}" ]]; then + echo "INFO: set global ${k}=${v};" + else + echo "ERROR: set global ${k}=${v};" && ret=1 + fi + else + ret=1 + fi + done <"${sv_file}" + return "${ret}" +} + +set_session_variable() { + if [[ ! -d "${DORIS_HOME:-}" ]]; then return 1; fi + k="$1" + v="$2" + if [[ -z "${v}" ]]; then return 1; fi + query_port=$(get_doris_conf_value "${DORIS_HOME}"/fe/conf/fe.conf query_port) + cl="mysql -h127.0.0.1 -P${query_port} -uroot " + if ${cl} -e"set global ${k}=${v};"; then + if [[ "$(get_session_variable "${k}" | tr '[:upper:]' '[:lower:]')" == "${v}" ]]; then + echo "INFO: set global ${k}=${v};" + else + echo "ERROR: set global ${k}=${v};" && return 1 + fi + else + return 1 + fi +} + +archive_doris_logs() { + if [[ ! -d "${DORIS_HOME:-}" ]]; then return 1; fi + archive_name="$1" + if [[ -z ${archive_name} ]]; then echo "ERROR: archive file name required" && return 1; fi + if tar -I pigz \ + --directory "${DORIS_HOME}" \ + --absolute-names \ + -cf "${DORIS_HOME}/${archive_name}" \ + "${DORIS_HOME}"/fe/conf \ + "${DORIS_HOME}"/fe/log \ + "${DORIS_HOME}"/be/conf \ + "${DORIS_HOME}"/be/log; then + echo "${DORIS_HOME}/${archive_name}" + else + return 1 + fi +} + +print_doris_fe_log() { + if [[ ! -d "${DORIS_HOME:-}" ]]; then return 1; fi + echo "WARNING: --------------------tail -n 100 ${DORIS_HOME}/fe/log/fe.out--------------------" + tail -n 100 "${DORIS_HOME}"/fe/log/fe.out + echo "WARNING: --------------------tail -n 100 ${DORIS_HOME}/fe/log/fe.log--------------------" + tail -n 100 "${DORIS_HOME}"/fe/log/fe.log + echo "WARNING: ----------------------------------------" +} + +print_doris_be_log() { + if [[ ! -d "${DORIS_HOME:-}" ]]; then return 1; fi + echo "WARNING: --------------------tail -n 100 ${DORIS_HOME}/be/log/be.out--------------------" + tail -n 100 "${DORIS_HOME}"/be/log/be.out + echo "WARNING: --------------------tail -n 100 ${DORIS_HOME}/be/log/be.INFO--------------------" + tail -n 100 "${DORIS_HOME}"/be/log/be.INFO + echo "WARNING: ----------------------------------------" +} diff --git a/regression-test/pipeline/common/github-utils.sh b/regression-test/pipeline/common/github-utils.sh new file mode 100644 index 00000000000000..c8c5ba213fb35d --- /dev/null +++ b/regression-test/pipeline/common/github-utils.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +function create_an_issue_comment() { + local ISSUE_NUMBER="$1" + local COMMENT_BODY="$2" + if [[ -z "${COMMENT_BODY}" ]]; then return 1; fi + if [[ -z "${GITHUB_TOKEN}" ]]; then return 1; fi + + local OWNER='apache' + local REPO='doris' + COMMENT_BODY=$(echo "${COMMENT_BODY}" | sed -e ':a;N;$!ba;s/\t/\\t/g;s/\n/\\n/g') # 将所有的 Tab字符替换为\t 换行符替换为\n + if ret=$(curl -s \ + -X POST \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${GITHUB_TOKEN:-}" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/"${OWNER}"/"${REPO}"/issues/"${ISSUE_NUMBER}"/comments \ + -d "{\"body\": \"${COMMENT_BODY}\"}"); then + if echo "${ret}" | grep "Problems parsing JSON"; then + is_succ=false + else + is_succ=true + fi + else + is_succ=false + fi + + if ${is_succ}; then + echo -e "\033[32m Create issue(${ISSUE_NUMBER}) comment SUCCESS... \033[0m" && return 0 + else + echo -e "\033[31m Create issue(${ISSUE_NUMBER}) comment FAIL... \033[0m" && return 1 + fi +} + +function create_an_issue_comment_tpch() { + local ISSUE_NUMBER="$1" + local COMMENT_BODY="$2" + local machine='aliyun_ecs.c7a.8xlarge_32C64G' + COMMENT_BODY=" +
+TPC-H test result on machine: '${machine}' + +\`\`\` +${COMMENT_BODY} +\`\`\` +
+" + create_an_issue_comment "${ISSUE_NUMBER}" "${COMMENT_BODY}" +} diff --git a/regression-test/pipeline/common/oss-utils.sh b/regression-test/pipeline/common/oss-utils.sh new file mode 100644 index 00000000000000..cc036fb573a65e --- /dev/null +++ b/regression-test/pipeline/common/oss-utils.sh @@ -0,0 +1,105 @@ +#!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +function install_ossutil() { + if command -v ossutil >/dev/null; then return 0; fi + if [[ -z ${OSS_accessKeyID} || -z ${OSS_accessKeySecret} ]]; then + echo "ERROR: env OSS_accessKeyID or OSS_accessKeySecret not set." + return 1 + fi + curl https://gosspublic.alicdn.com/ossutil/install.sh | sudo bash + echo "[Credentials] +language=EN +endpoint=oss-cn-hongkong-internal.aliyuncs.com +accessKeyID=${OSS_accessKeyID:-} +accessKeySecret=${OSS_accessKeySecret:-} +" >~/.ossutilconfig +} + +function check_oss_file_exist() { + if [[ -z ${OSS_accessKeyID} || -z ${OSS_accessKeySecret} ]]; then + echo "ERROR: env OSS_accessKeyID and OSS_accessKeySecret not set" + return 1 + fi + # Check if the file exists. + # file_name like ${pull_request_id}_${commit_id}.tar.gz + local file_name="$1" + OSS_DIR="${OSS_DIR:-"oss://opensource-pipeline/compile-release"}" + install_ossutil + if ossutil stat \ + -i "${OSS_accessKeyID}" \ + -k "${OSS_accessKeySecret}" \ + "${OSS_DIR}/${file_name}"; then + echo "INFO: ${file_name} file exists." && return 0 + else + echo "ERROR: ${file_name} file not exits." && return 1 + fi +} + +function download_oss_file() { + # file_name like ${pull_request_id}_${commit_id}.tar.gz + local file_name="$1" + if ! check_oss_file_exist "${file_name}"; then return 1; fi + OSS_DIR="${OSS_DIR:-"oss://opensource-pipeline/compile-release"}" + install_ossutil + if ossutil cp -f \ + "${OSS_DIR}/${file_name}" \ + "${file_name}"; then + echo "INFO: download ${file_name} success" && return 0 + else + echo "ERROR: download ${file_name} fail" && return 1 + fi +} + +function upload_file_to_oss() { + if [[ -z ${OSS_accessKeyID} || -z ${OSS_accessKeySecret} ]]; then + echo "ERROR: env OSS_accessKeyID and OSS_accessKeySecret not set" + return 1 + fi + if [[ ! -f "$1" ]] || [[ "$1" != "/"* ]]; then + echo "ERROR: '$1' is not an absolute path" + return 1 + fi + # file_name like ${pull_request_id}_${commit_id}.tar.gz + local file_name + local dir_name + dir_name="$(dirname "${1}")" + file_name="$(basename "${1}")" + OSS_DIR="${OSS_DIR:-"oss://opensource-pipeline/compile-release"}" + OSS_URL_PREFIX="${OSS_URL_PREFIX:-"http://opensource-pipeline.oss-cn-hongkong.aliyuncs.com/compile-release"}" + install_ossutil + cd "${dir_name}" || return 1 + if ossutil cp -f \ + -i "${OSS_accessKeyID}" \ + -k "${OSS_accessKeySecret}" \ + "${file_name}" \ + "${OSS_DIR}/${file_name}"; then + if ! check_oss_file_exist "${file_name}"; then return 1; fi + cd - || return 1 + echo "INFO: success to upload ${file_name} to ${OSS_URL_PREFIX}/${file_name}" && return 0 + else + cd - || return 1 + echo "ERROR: upload ${file_name} fail" && return 1 + fi +} + +function upload_doris_log_to_oss() { + OSS_DIR="oss://opensource-pipeline/regression" + OSS_URL_PREFIX="http://opensource-pipeline.oss-cn-hongkong.aliyuncs.com/regression" + upload_file_to_oss "$1" +} diff --git a/regression-test/pipeline/tpch/tpch-sf100/clean.sh b/regression-test/pipeline/tpch/tpch-sf100/clean.sh new file mode 100644 index 00000000000000..16fa490ef9c237 --- /dev/null +++ b/regression-test/pipeline/tpch/tpch-sf100/clean.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Build Step: Command Line +: <:', separate by ',' +# property 'medium' has a higher priority than the extension of path +# +# Default value is ${DORIS_HOME}/storage, you should create it by hand. +# storage_root_path = ${DORIS_HOME}/storage + +# Default dirs to put jdbc drivers,default value is ${DORIS_HOME}/jdbc_drivers +# jdbc_drivers_dir = ${DORIS_HOME}/jdbc_drivers + +# Advanced configurations +# sys_log_dir = ${DORIS_HOME}/log +# sys_log_roll_mode = SIZE-MB-1024 +# sys_log_roll_num = 10 +# sys_log_verbose_modules = * +# log_buffer_level = -1 +# palo_cgroups + +priority_networks=172.16.0.0/24 +storage_root_path=/mnt/datadisk0/doris-storage diff --git a/regression-test/pipeline/tpch/tpch-sf100/conf/external.json b/regression-test/pipeline/tpch/tpch-sf100/conf/external.json new file mode 100644 index 00000000000000..9461d836e6749a --- /dev/null +++ b/regression-test/pipeline/tpch/tpch-sf100/conf/external.json @@ -0,0 +1,26 @@ +[ + { + "file": "docker/thirdparties/docker-compose/mysql/mysql-5.7.env", + "replacements": { + "DOCKER_MYSQL_57_EXTERNAL_PORT": 7111 + } + }, + { + "file": "docker/thirdparties/docker-compose/postgresql/postgresql-14.env", + "replacements": { + "DOCKER_PG_14_EXTERNAL_PORT": 7121 + } + }, + { + "file": "docker/thirdparties/docker-compose/hive/gen_env.sh", + "replacements": { + "FS_PORT": 7131, + "HMS_PORT": 7141 + } + }, { + "file": "docker/thirdparties/start-thirdparties-docker.sh", + "replacements": { + "CONTAINER_UID": "doris-regression-fakeid-fakecommit" + } + } +] diff --git a/regression-test/pipeline/tpch/tpch-sf100/conf/fe.conf b/regression-test/pipeline/tpch/tpch-sf100/conf/fe.conf new file mode 100644 index 00000000000000..7c02d3898dcb45 --- /dev/null +++ b/regression-test/pipeline/tpch/tpch-sf100/conf/fe.conf @@ -0,0 +1,78 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +##################################################################### +## The uppercase properties are read and exported by bin/start_fe.sh. +## To see all Frontend configurations, +## see fe/src/org/apache/doris/common/Config.java +##################################################################### + +CUR_DATE=`date +%Y%m%d-%H%M%S` + +# the output dir of stderr and stdout +LOG_DIR = ${DORIS_HOME}/log + +JAVA_OPTS="-Dsun.security.krb5.debug=true -Djavax.security.auth.useSubjectCredsOnly=false -Xss4m -Xmx8192m -XX:+UseMembar -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=7 -XX:+PrintGCDateStamps -XX:+PrintGCDetails -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:+CMSClassUnloadingEnabled -XX:-CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0 -Xloggc:$DORIS_HOME/log/fe.gc.log.$CUR_DATE" + +# For jdk 9+, this JAVA_OPTS will be used as default JVM options +JAVA_OPTS_FOR_JDK_9="-Dsun.security.krb5.debug=true -Djavax.security.auth.useSubjectCredsOnly=false -Xss4m -Xmx8192m -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=7 -XX:+CMSClassUnloadingEnabled -XX:-CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=80 -XX:SoftRefLRUPolicyMSPerMB=0 -Xlog:gc*:$DORIS_HOME/log/fe.gc.log.$CUR_DATE:time" + +## +## the lowercase properties are read by main program. +## + +# INFO, WARN, ERROR, FATAL +sys_log_level = INFO + +# NORMAL, BRIEF, ASYNC +sys_log_mode = NORMAL + +# store metadata, must be created before start FE. +# Default value is ${DORIS_HOME}/doris-meta +# meta_dir = ${DORIS_HOME}/doris-meta + +# Default dirs to put jdbc drivers,default value is ${DORIS_HOME}/jdbc_drivers +# jdbc_drivers_dir = ${DORIS_HOME}/jdbc_drivers + +http_port = 8030 +rpc_port = 9020 +query_port = 9030 +edit_log_port = 9010 +arrow_flight_sql_port = -1 + +# Choose one if there are more than one ip except loopback address. +# Note that there should at most one ip match this list. +# If no ip match this rule, will choose one randomly. +# use CIDR format, e.g. 10.10.10.0/24 or IP format, e.g. 10.10.10.1 +# Default value is empty. +# priority_networks = 10.10.10.0/24;192.168.0.0/16 + +# Advanced configurations +# log_roll_size_mb = 1024 +# sys_log_dir = ${DORIS_HOME}/log +# sys_log_roll_num = 10 +# sys_log_verbose_modules = org.apache.doris +# audit_log_dir = ${DORIS_HOME}/log +# audit_log_modules = slow_query, query +# audit_log_roll_num = 10 +# meta_delay_toleration_second = 10 +# qe_max_connection = 1024 +# qe_query_timeout_second = 300 +# qe_slow_log_ms = 5000 + +priority_networks=172.16.0.0/24 +meta_dir=/mnt/datadisk0/doris-meta diff --git a/regression-test/pipeline/tpch/tpch-sf100/conf/odbcinst.ini b/regression-test/pipeline/tpch/tpch-sf100/conf/odbcinst.ini new file mode 100644 index 00000000000000..41e21f92277e98 --- /dev/null +++ b/regression-test/pipeline/tpch/tpch-sf100/conf/odbcinst.ini @@ -0,0 +1,43 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Example driver definitions, you should not use the example odbc driver +# before you prepare env in your server + +# Driver from the postgresql-odbc package +# Setup from the unixODBC package +[PostgreSQL] +Description = ODBC for PostgreSQL +Driver = /usr/lib/psqlodbc.so +Setup = /usr/lib/libodbcpsqlS.so +FileUsage = 1 + + +# Driver from the mysql-connector-odbc package +# Setup from the unixODBC package +[MySQL ODBC 8.0 Unicode Driver] +Description = ODBC for MySQL +Driver = /usr/lib64/libmyodbc8w.so +FileUsage = 1 + +# Driver from the oracle-connector-odbc package +# Setup from the unixODBC package +[Oracle 19 ODBC driver] +Description=Oracle ODBC driver for Oracle 19 +Driver=/usr/lib/libsqora.so.19.1 + + diff --git a/regression-test/pipeline/tpch/tpch-sf100/conf/regression-conf.groovy b/regression-test/pipeline/tpch/tpch-sf100/conf/regression-conf.groovy new file mode 100644 index 00000000000000..364a7103fe8612 --- /dev/null +++ b/regression-test/pipeline/tpch/tpch-sf100/conf/regression-conf.groovy @@ -0,0 +1,111 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +/* ******* Do not commit this file unless you know what you are doing ******* */ + +// **Note**: default db will be create if not exist +defaultDb = "regression_test" + +jdbcUrl = "jdbc:mysql://172.19.0.2:9131/?useLocalSessionState=true&allowLoadLocalInfile=true" +targetJdbcUrl = "jdbc:mysql://172.19.0.2:9131/?useLocalSessionState=true&allowLoadLocalInfile=true" +jdbcUser = "root" +jdbcPassword = "" + +feSourceThriftAddress = "127.0.0.1:9020" +feTargetThriftAddress = "127.0.0.1:9020" +feSyncerUser = "root" +feSyncerPassword = "" + +feHttpAddress = "172.19.0.2:8131" +feHttpUser = "root" +feHttpPassword = "" + +// set DORIS_HOME by system properties +// e.g. java -DDORIS_HOME=./ +suitePath = "${DORIS_HOME}/regression-test/suites" +dataPath = "${DORIS_HOME}/regression-test/data" +pluginPath = "${DORIS_HOME}/regression-test/plugins" +realDataPath = "${DORIS_HOME}/regression-test/realdata" +// sf1DataPath can be url like "https://doris-community-test-1308700295.cos.ap-hongkong.myqcloud.com" or local path like "/data" +//sf1DataPath = "https://doris-community-test-1308700295.cos.ap-hongkong.myqcloud.com" + +// will test /.groovy +// empty group will test all group +testGroups = "" +// empty suite will test all suite +testSuites = "" +// empty directories will test all directories +testDirectories = "" + +// this groups will not be executed +excludeGroups = "" +// this suites will not be executed + +excludeSuites = "test_sql_block_rule,test_profile,test_spark_load,test_refresh_mtmv,test_bitmap_filter,test_jdbc_query_mysql" + +// this directories will not be executed +excludeDirectories = "workload_manager_p1,fault_injection_p0" + +customConf1 = "test_custom_conf_value" + +// for test csv with header +enableHdfs=false // set to true if hdfs is ready +hdfsFs = "hdfs://127.0.0.1:9000" +hdfsUser = "doris-test" +hdfsPasswd = "" +brokerName = "broker_name" + +// broker load test config +enableBrokerLoad=true + +// jdbc connector test config +// To enable jdbc test, you need first start mysql/pg container. +// See `docker/thirdparties/start-thirdparties-docker.sh` +enableJdbcTest=false +mysql_57_port=7111 +pg_14_port=7121 +mariadb_10_port=3326 +// hive catalog test config +// To enable jdbc test, you need first start hive container. +// See `docker/thirdparties/start-thirdparties-docker.sh` +enableHiveTest=false +hms_port=7141 +hiveServerPort=10000 + +// kafka test config +// to enable kafka test, you need firstly to start kafka container +// See `docker/thirdparties/start-thirdparties-docker.sh` +enableKafkaTest=true +kafka_port=19193 + +// iceberg test config +iceberg_rest_uri_port=18181 + +enableEsTest=false +es_6_port=19200 +es_7_port=29200 +es_8_port=39200 + +cacheDataPath = "/data/regression/" + +s3Endpoint = "cos.ap-hongkong.myqcloud.com" +s3BucketName = "doris-build-hk-1308700295" +s3Region = "ap-hongkong" + +max_failure_num=50 + +externalEnvIp="127.0.0.1" diff --git a/regression-test/pipeline/tpch/tpch-sf100/deploy.sh b/regression-test/pipeline/tpch/tpch-sf100/deploy.sh new file mode 100644 index 00000000000000..1ff17ebfba0c91 --- /dev/null +++ b/regression-test/pipeline/tpch/tpch-sf100/deploy.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Build Step: Command Line +: </dev/null; then sudo apt install -y pigz; fi + tar -I pigz -xf "${pull_request_id:-}_${commit_id:-}.tar.gz" + if [[ -d output && -d output/fe && -d output/be ]]; then + echo "INFO: be version: $(./output/be/lib/doris_be --version)" + rm -rf "${pull_request_id}_${commit_id}.tar.gz" + fi +else + echo "ERROR: download compiled binary failed" && exit 1 +fi + +echo "#### 3. copy conf from regression-test/pipeline/tpch/tpch-sf100/conf/" +rm -f "${DORIS_HOME}"/fe/conf/fe_custom.conf "${DORIS_HOME}"/be/conf/be_custom.conf +if [[ -f "${teamcity_build_checkoutDir}"/regression-test/pipeline/tpch/tpch-sf100/conf/fe.conf && + -f "${teamcity_build_checkoutDir}"/regression-test/pipeline/tpch/tpch-sf100/conf/be.conf ]]; then + cp -f "${teamcity_build_checkoutDir}"/regression-test/pipeline/tpch/tpch-sf100/conf/fe.conf "${DORIS_HOME}"/fe/conf/ + cp -f "${teamcity_build_checkoutDir}"/regression-test/pipeline/tpch/tpch-sf100/conf/be.conf "${DORIS_HOME}"/be/conf/ +else + echo "ERROR: doris conf file missing in ${teamcity_build_checkoutDir}/regression-test/pipeline/tpch/tpch-sf100/conf/" + exit 1 +fi + +echo "#### 4. start Doris" +meta_dir=$(get_doris_conf_value "${DORIS_HOME}"/fe/conf/fe.conf meta_dir) +storage_root_path=$(get_doris_conf_value "${DORIS_HOME}"/be/conf/be.conf storage_root_path) +mkdir -p "${meta_dir}" +mkdir -p "${storage_root_path}" +if ! start_doris_fe; then + echo "WARNING: Start doris fe failed at first time" + print_doris_fe_log + echo "WARNING: delete meta_dir and storage_root_path, then retry" + rm -rf "${meta_dir:?}/"* + rm -rf "${storage_root_path:?}/"* + if ! start_doris_fe; then + need_backup_doris_logs=true + exit_flag=1 + fi +fi +if ! start_doris_be; then + echo "WARNING: Start doris be failed at first time" + print_doris_be_log + echo "WARNING: delete storage_root_path, then retry" + rm -rf "${storage_root_path:?}/"* + if ! start_doris_be; then + need_backup_doris_logs=true + exit_flag=1 + fi +fi +if ! add_doris_be_to_fe; then + need_backup_doris_logs=true + exit_flag=1 +else + # wait 10s for doris totally started, otherwize may encounter the error below, + # ERROR 1105 (HY000) at line 102: errCode = 2, detailMessage = Failed to find enough backend, please check the replication num,replication tag and storage medium. + sleep 10s +fi + +echo "#### 5. set session variables" +echo "TODO" + +echo "#### 6. check if need backup doris logs" +if ${need_backup_doris_logs}; then + print_doris_fe_log + print_doris_be_log + if archive_doris_logs "${DORIS_HOME}/${pull_request_id}_${commit_id}_doris_logs.tar.gz"; then + upload_doris_log_to_oss "${DORIS_HOME}/${pull_request_id}_${commit_id}_doris_logs.tar.gz" + fi +fi + +exit "${exit_flag}" diff --git a/regression-test/pipeline/tpch/tpch-sf100/prepare.sh b/regression-test/pipeline/tpch/tpch-sf100/prepare.sh new file mode 100644 index 00000000000000..5376f7c73087ac --- /dev/null +++ b/regression-test/pipeline/tpch/tpch-sf100/prepare.sh @@ -0,0 +1,71 @@ +#!/usr/bin/env bash +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +# Build Step: Command Line +: </dev/null; then exit 1; fi + line_end=$(sed -n '/^Total hot run time/=' "${teamcity_build_checkoutDir}"/run-tpch-queries.log) + line_begin=$((line_end - 23)) + comment_body="Tpch sf${SF} test result on commit ${commit_id:-}, data reload: ${data_reload:-"false"} + +run tpch-sf${SF} query with default conf and session variables +$(sed -n "${line_begin},${line_end}p" "${teamcity_build_checkoutDir}"/run-tpch-queries.log)" + + echo "#### 3. run tpch-sf${SF} query with runtime_filter_mode=off" + set_session_variable runtime_filter_mode off + bash "${teamcity_build_checkoutDir}"/tools/tpch-tools/bin/run-tpch-queries.sh | tee "${teamcity_build_checkoutDir}"/run-tpch-queries.log + if ! grep '^Total hot run time' "${teamcity_build_checkoutDir}"/run-tpch-queries.log >/dev/null; then exit 1; fi + line_end=$(sed -n '/^Total hot run time/=' "${teamcity_build_checkoutDir}"/run-tpch-queries.log) + line_begin=$((line_end - 23)) + comment_body="${comment_body} + +run tpch-sf${SF} query with default conf and set session variable runtime_filter_mode=off +$(sed -n "${line_begin},${line_end}p" "${teamcity_build_checkoutDir}"/run-tpch-queries.log)" + + echo "#### 4. comment result on tpch" + comment_body=$(echo "${comment_body}" | sed -e ':a;N;$!ba;s/\t/\\t/g;s/\n/\\n/g') # 将所有的 Tab字符替换为\t 换行符替换为\n + create_an_issue_comment_tpch "${pull_request_id:-}" "${comment_body}" + + stop_doris +) +exit_flag="$?" + +echo "#### 5. check if need backup doris logs" +if [[ ${exit_flag} != "0" ]]; then + print_doris_fe_log + print_doris_be_log + if archive_doris_logs "${DORIS_HOME}/${pull_request_id}_${commit_id}_doris_logs.tar.gz"; then + upload_doris_log_to_oss "${DORIS_HOME}/${pull_request_id}_${commit_id}_doris_logs.tar.gz" + fi +fi + +exit "${exit_flag}" diff --git a/tools/tpch-tools/bin/create-tpch-tables.sh b/tools/tpch-tools/bin/create-tpch-tables.sh index 8b9635a4ceefb0..0dd8cd81de2d2a 100755 --- a/tools/tpch-tools/bin/create-tpch-tables.sh +++ b/tools/tpch-tools/bin/create-tpch-tables.sh @@ -106,7 +106,7 @@ echo "SF: ${SCALE_FACTOR}" mysql -h"${FE_HOST}" -u"${USER}" -P"${FE_QUERY_PORT}" -e "CREATE DATABASE IF NOT EXISTS ${DB}" if [[ ${SCALE_FACTOR} -eq 1 ]]; then - echo "Run SQLs from ${CURDIR}/../ddl/create-tpch-tables.sql" + echo "Run SQLs from ${CURDIR}/../ddl/create-tpch-tables-sf1.sql" mysql -h"${FE_HOST}" -u"${USER}" -P"${FE_QUERY_PORT}" -D"${DB}" <"${CURDIR}"/../ddl/create-tpch-tables-sf1.sql elif [[ ${SCALE_FACTOR} -eq 100 ]]; then echo "Run SQLs from ${CURDIR}/../ddl/create-tpch-tables-sf100.sql" diff --git a/tools/tpch-tools/bin/load-tpch-data.sh b/tools/tpch-tools/bin/load-tpch-data.sh index 3e4e7f6bfb60c8..c56d2ea71acd79 100755 --- a/tools/tpch-tools/bin/load-tpch-data.sh +++ b/tools/tpch-tools/bin/load-tpch-data.sh @@ -116,49 +116,49 @@ echo "DB: ${DB}" function load_region() { echo "$*" - curl --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ + curl -s --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ -H "columns: r_regionkey, r_name, r_comment, temp" \ -T "$*" http://"${FE_HOST}":"${FE_HTTP_PORT}"/api/"${DB}"/region/_stream_load } function load_nation() { echo "$*" - curl --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ + curl -s --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ -H "columns: n_nationkey, n_name, n_regionkey, n_comment, temp" \ -T "$*" http://"${FE_HOST}":"${FE_HTTP_PORT}"/api/"${DB}"/nation/_stream_load } function load_supplier() { echo "$*" - curl --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ + curl -s --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ -H "columns: s_suppkey, s_name, s_address, s_nationkey, s_phone, s_acctbal, s_comment, temp" \ -T "$*" http://"${FE_HOST}":"${FE_HTTP_PORT}"/api/"${DB}"/supplier/_stream_load } function load_customer() { echo "$*" - curl --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ + curl -s --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ -H "columns: c_custkey, c_name, c_address, c_nationkey, c_phone, c_acctbal, c_mktsegment, c_comment, temp" \ -T "$*" http://"${FE_HOST}":"${FE_HTTP_PORT}"/api/"${DB}"/customer/_stream_load } function load_part() { echo "$*" - curl --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ + curl -s --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ -H "columns: p_partkey, p_name, p_mfgr, p_brand, p_type, p_size, p_container, p_retailprice, p_comment, temp" \ -T "$*" http://"${FE_HOST}":"${FE_HTTP_PORT}"/api/"${DB}"/part/_stream_load } function load_partsupp() { echo "$*" - curl --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ + curl -s --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ -H "columns: ps_partkey, ps_suppkey, ps_availqty, ps_supplycost, ps_comment, temp" \ -T "$*" http://"${FE_HOST}":"${FE_HTTP_PORT}"/api/"${DB}"/partsupp/_stream_load } function load_orders() { echo "$*" - curl --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ + curl -s --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ -H "columns: o_orderkey, o_custkey, o_orderstatus, o_totalprice, o_orderdate, o_orderpriority, o_clerk, o_shippriority, o_comment, temp" \ -T "$*" http://"${FE_HOST}":"${FE_HTTP_PORT}"/api/"${DB}"/orders/_stream_load } function load_lineitem() { echo "$*" - curl --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ + curl -s --location-trusted -u "${USER}":"${PASSWORD}" -H "column_separator:|" \ -H "columns: l_orderkey, l_partkey, l_suppkey, l_linenumber, l_quantity, l_extendedprice, l_discount, l_tax, l_returnflag,l_linestatus, l_shipdate,l_commitdate,l_receiptdate,l_shipinstruct,l_shipmode,l_comment,temp" \ -T "$*" http://"${FE_HOST}":"${FE_HTTP_PORT}"/api/"${DB}"/lineitem/_stream_load } diff --git a/tools/tpch-tools/bin/run-tpch-queries.sh b/tools/tpch-tools/bin/run-tpch-queries.sh index ce27cf18eb8a68..d88062183cdf11 100755 --- a/tools/tpch-tools/bin/run-tpch-queries.sh +++ b/tools/tpch-tools/bin/run-tpch-queries.sh @@ -180,5 +180,6 @@ for i in ${query_array[@]}; do done echo "Total cold run time: ${cold_run_sum} ms" +# tpch 流水线依赖这个'Total hot run time'字符串 echo "Total hot run time: ${best_hot_run_sum} ms" echo 'Finish tpch queries.' From 6637f9c15f9346abbd00feb41eca9624a7bc1c1e Mon Sep 17 00:00:00 2001 From: wangbo Date: Wed, 8 Nov 2023 15:52:13 +0800 Subject: [PATCH 46/88] Add enable_cgroup_cpu_soft_limit (#26510) --- be/src/agent/cgroup_cpu_ctl.cpp | 24 +++++++++++++++++-- be/src/agent/cgroup_cpu_ctl.h | 22 ++++++++++++++--- be/src/common/config.cpp | 1 + be/src/common/config.h | 2 ++ be/src/runtime/fragment_mgr.cpp | 21 ++++++++++++---- .../runtime/task_group/task_group_manager.cpp | 12 ++++++++-- .../runtime/task_group/task_group_manager.h | 3 ++- 7 files changed, 73 insertions(+), 12 deletions(-) diff --git a/be/src/agent/cgroup_cpu_ctl.cpp b/be/src/agent/cgroup_cpu_ctl.cpp index ee24b34e1676d1..d16a32b7be5433 100644 --- a/be/src/agent/cgroup_cpu_ctl.cpp +++ b/be/src/agent/cgroup_cpu_ctl.cpp @@ -54,6 +54,19 @@ void CgroupCpuCtl::update_cpu_hard_limit(int cpu_hard_limit) { } } +void CgroupCpuCtl::update_cpu_soft_limit(int cpu_shares) { + if (!_init_succ) { + return; + } + std::lock_guard w_lock(_lock_mutex); + if (_cpu_shares != cpu_shares) { + Status ret = modify_cg_cpu_soft_limit_no_lock(cpu_shares); + if (ret.ok()) { + _cpu_shares = cpu_shares; + } + } +} + Status CgroupCpuCtl::write_cg_sys_file(std::string file_path, int value, std::string msg, bool is_append) { int fd = open(file_path.c_str(), is_append ? O_RDWR | O_APPEND : O_RDWR); @@ -97,9 +110,11 @@ Status CgroupV1CpuCtl::init() { } } - // quota path + // quota file _cgroup_v1_cpu_tg_quota_file = _cgroup_v1_cpu_tg_path + "/cpu.cfs_quota_us"; - // task path + // cpu.shares file + _cgroup_v1_cpu_tg_shares_file = _cgroup_v1_cpu_tg_path + "/cpu.shares"; + // task file _cgroup_v1_cpu_tg_task_file = _cgroup_v1_cpu_tg_path + "/tasks"; LOG(INFO) << "cgroup v1 cpu path init success" << ", query tg path=" << _cgroup_v1_cpu_tg_path @@ -110,6 +125,11 @@ Status CgroupV1CpuCtl::init() { return Status::OK(); } +Status CgroupV1CpuCtl::modify_cg_cpu_soft_limit_no_lock(int cpu_shares) { + std::string msg = "modify cpu shares to " + std::to_string(cpu_shares); + return CgroupCpuCtl::write_cg_sys_file(_cgroup_v1_cpu_tg_shares_file, cpu_shares, msg, false); +} + Status CgroupV1CpuCtl::modify_cg_cpu_hard_limit_no_lock(int cpu_hard_limit) { int val = _cpu_cfs_period_us * _cpu_core_num * cpu_hard_limit / 100; std::string msg = "modify cpu quota value to " + std::to_string(val); diff --git a/be/src/agent/cgroup_cpu_ctl.h b/be/src/agent/cgroup_cpu_ctl.h index c3a30660147d63..b98e268da09464 100644 --- a/be/src/agent/cgroup_cpu_ctl.h +++ b/be/src/agent/cgroup_cpu_ctl.h @@ -28,6 +28,12 @@ namespace doris { +// cgroup cpu.cfs_quota_us default value, it means disable cpu hard limit +const static int CPU_HARD_LIMIT_DEFAULT_VALUE = -1; + +// cgroup cpu.shares default value +const static uint64_t CPU_SOFT_LIMIT_DEFAULT_VALUE = 1024; + class CgroupCpuCtl { public: virtual ~CgroupCpuCtl() = default; @@ -35,15 +41,19 @@ class CgroupCpuCtl { virtual Status init(); - virtual Status modify_cg_cpu_hard_limit_no_lock(int cpu_hard_limit) = 0; - virtual Status add_thread_to_cgroup() = 0; void update_cpu_hard_limit(int cpu_hard_limit); + void update_cpu_soft_limit(int cpu_shares); + protected: Status write_cg_sys_file(std::string file_path, int value, std::string msg, bool is_append); + virtual Status modify_cg_cpu_hard_limit_no_lock(int cpu_hard_limit) = 0; + + virtual Status modify_cg_cpu_soft_limit_no_lock(int cpu_shares) = 0; + std::string _doris_cgroup_cpu_path; uint64_t _cpu_core_num = CpuInfo::num_cores(); uint64_t _cpu_cfs_period_us = 100000; @@ -51,6 +61,7 @@ class CgroupCpuCtl { std::shared_mutex _lock_mutex; bool _init_succ = false; uint64_t _tg_id; // workload group id + uint64_t _cpu_shares = 0; }; /* @@ -73,20 +84,25 @@ class CgroupCpuCtl { 6 workload group quota file: /sys/fs/cgroup/cpu/{doris_home}/query/{workload group id}/cpu.cfs_quota_us - 7 workload group tasks file: + 7 workload group tasks file: /sys/fs/cgroup/cpu/{doris_home}/query/{workload group id}/tasks + + 8 workload group cpu.shares file: + /sys/fs/cgroup/cpu/{doris_home}/query/{workload group id}/cpu.shares */ class CgroupV1CpuCtl : public CgroupCpuCtl { public: CgroupV1CpuCtl(uint64_t tg_id) : CgroupCpuCtl(tg_id) {} Status init() override; Status modify_cg_cpu_hard_limit_no_lock(int cpu_hard_limit) override; + Status modify_cg_cpu_soft_limit_no_lock(int cpu_shares) override; Status add_thread_to_cgroup() override; private: std::string _cgroup_v1_cpu_query_path; std::string _cgroup_v1_cpu_tg_path; // workload group path std::string _cgroup_v1_cpu_tg_quota_file; + std::string _cgroup_v1_cpu_tg_shares_file; std::string _cgroup_v1_cpu_tg_task_file; }; diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp index e858a5b6acb63f..17f69c3d360ff4 100644 --- a/be/src/common/config.cpp +++ b/be/src/common/config.cpp @@ -1113,6 +1113,7 @@ DEFINE_Bool(enable_flush_file_cache_async, "true"); // cgroup DEFINE_String(doris_cgroup_cpu_path, ""); +DEFINE_Bool(enable_cgroup_cpu_soft_limit, "false"); DEFINE_Bool(ignore_always_true_predicate_for_segment, "true"); diff --git a/be/src/common/config.h b/be/src/common/config.h index 493f9342aa7758..cfcd09c1984792 100644 --- a/be/src/common/config.h +++ b/be/src/common/config.h @@ -1183,6 +1183,8 @@ DECLARE_mBool(exit_on_exception); // cgroup DECLARE_String(doris_cgroup_cpu_path); +DECLARE_Bool(enable_cgroup_cpu_soft_limit); + // This config controls whether the s3 file writer would flush cache asynchronously DECLARE_Bool(enable_flush_file_cache_async); diff --git a/be/src/runtime/fragment_mgr.cpp b/be/src/runtime/fragment_mgr.cpp index 83b57c28fd7957..266c652ca7f5a8 100644 --- a/be/src/runtime/fragment_mgr.cpp +++ b/be/src/runtime/fragment_mgr.cpp @@ -671,18 +671,31 @@ Status FragmentMgr::_get_query_ctx(const Params& params, TUniqueId query_id, boo LOG(INFO) << "Query/load id: " << print_id(query_ctx->query_id()) << " use task group: " << tg->debug_string() << " cpu_hard_limit: " << task_group_info.cpu_hard_limit - << " cpu_share:" << task_group_info.cpu_share; + << " cpu_share:" << task_group_info.cpu_share + << " enable cgroup soft cpu:" << config::enable_cgroup_cpu_soft_limit; if (task_group_info.cpu_hard_limit > 0) { Status ret = _exec_env->task_group_manager()->create_and_get_task_scheduler( - tg_id, tg_name, task_group_info.cpu_hard_limit, _exec_env, - query_ctx.get()); + tg_id, tg_name, task_group_info.cpu_hard_limit, + task_group_info.cpu_share, _exec_env, query_ctx.get()); if (!ret.ok()) { LOG(INFO) << "workload group init failed " << ", name=" << tg_name << ", id=" << tg_id << ", reason=" << ret.to_string(); } } else { - query_ctx->set_task_group(tg); + if (!config::enable_cgroup_cpu_soft_limit) { + query_ctx->set_task_group(tg); + } else { + Status ret = + _exec_env->task_group_manager()->create_and_get_task_scheduler( + tg_id, tg_name, task_group_info.cpu_hard_limit, + task_group_info.cpu_share, _exec_env, query_ctx.get()); + if (!ret.ok()) { + LOG(INFO) << "workload group cpu soft limit init failed " + << ", name=" << tg_name << ", id=" << tg_id + << ", reason=" << ret.to_string(); + } + } } } } else { diff --git a/be/src/runtime/task_group/task_group_manager.cpp b/be/src/runtime/task_group/task_group_manager.cpp index b3c24fa96e7c58..fb940069787666 100644 --- a/be/src/runtime/task_group/task_group_manager.cpp +++ b/be/src/runtime/task_group/task_group_manager.cpp @@ -60,7 +60,8 @@ void TaskGroupManager::get_resource_groups(const std::function lock(_task_scheduler_lock); // step 1: init cgroup cpu controller @@ -117,7 +118,14 @@ Status TaskGroupManager::create_and_get_task_scheduler(uint64_t tg_id, std::stri query_ctx_ptr->set_scan_task_scheduler(scan_task_sche); // step 5 update cgroup cpu if needed - _cgroup_ctl_map.at(tg_id)->update_cpu_hard_limit(cpu_hard_limit); + if (cpu_hard_limit > 0) { + _cgroup_ctl_map.at(tg_id)->update_cpu_hard_limit(cpu_hard_limit); + _cgroup_ctl_map.at(tg_id)->update_cpu_soft_limit(CPU_SOFT_LIMIT_DEFAULT_VALUE); + } else { + _cgroup_ctl_map.at(tg_id)->update_cpu_soft_limit(cpu_shares); + _cgroup_ctl_map.at(tg_id)->update_cpu_hard_limit( + CPU_HARD_LIMIT_DEFAULT_VALUE); // disable cpu hard limit + } return Status::OK(); } diff --git a/be/src/runtime/task_group/task_group_manager.h b/be/src/runtime/task_group/task_group_manager.h index ae501e93f3e781..cf44f5354406c7 100644 --- a/be/src/runtime/task_group/task_group_manager.h +++ b/be/src/runtime/task_group/task_group_manager.h @@ -52,7 +52,8 @@ class TaskGroupManager { std::vector* task_groups); Status create_and_get_task_scheduler(uint64_t wg_id, std::string wg_name, int cpu_hard_limit, - ExecEnv* exec_env, QueryContext* query_ctx_ptr); + int cpu_shares, ExecEnv* exec_env, + QueryContext* query_ctx_ptr); void delete_task_group_by_ids(std::set id_set); From 58bf79f79e6bccea1942d0234855f667fce8546e Mon Sep 17 00:00:00 2001 From: Kaijie Chen Date: Wed, 8 Nov 2023 16:16:33 +0800 Subject: [PATCH 47/88] [fix](move-memtable) pass load stream num to backends (#26198) --- be/src/common/config.cpp | 2 - be/src/common/config.h | 2 - be/src/pipeline/pipeline_fragment_context.cpp | 2 + .../pipeline_x_fragment_context.cpp | 2 + be/src/runtime/load_stream.cpp | 97 ++++++------- be/src/runtime/load_stream.h | 26 +++- be/src/runtime/plan_fragment_executor.cpp | 2 + be/src/runtime/runtime_state.h | 14 ++ be/src/service/internal_service.cpp | 1 - be/src/vec/sink/load_stream_stub.cpp | 5 +- be/src/vec/sink/load_stream_stub.h | 3 +- be/src/vec/sink/load_stream_stub_pool.cpp | 4 +- be/src/vec/sink/load_stream_stub_pool.h | 3 +- be/src/vec/sink/vtablet_sink_v2.cpp | 16 ++- be/src/vec/sink/vtablet_sink_v2.h | 2 + be/test/runtime/load_stream_test.cpp | 127 ++++++++++++++++-- .../vec/exec/load_stream_stub_pool_test.cpp | 6 +- .../doris/planner/StreamLoadPlanner.java | 4 + .../java/org/apache/doris/qe/Coordinator.java | 35 +++++ .../org/apache/doris/qe/SessionVariable.java | 13 ++ .../org/apache/doris/task/LoadTaskInfo.java | 4 + .../org/apache/doris/task/StreamLoadTask.java | 13 ++ gensrc/proto/internal_service.proto | 1 + gensrc/thrift/FrontendService.thrift | 1 + gensrc/thrift/PaloInternalService.thrift | 8 ++ 25 files changed, 312 insertions(+), 81 deletions(-) diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp index 17f69c3d360ff4..0ccb48f116e475 100644 --- a/be/src/common/config.cpp +++ b/be/src/common/config.cpp @@ -742,8 +742,6 @@ DEFINE_mDouble(tablet_version_graph_orphan_vertex_ratio, "0.1"); // share delta writers when memtable_on_sink_node = true DEFINE_Bool(share_delta_writers, "true"); -// number of brpc stream per load -DEFINE_Int32(num_streams_per_load, "5"); // timeout for open load stream rpc in ms DEFINE_Int64(open_load_stream_timeout_ms, "500"); diff --git a/be/src/common/config.h b/be/src/common/config.h index cfcd09c1984792..f0fdf58558c35e 100644 --- a/be/src/common/config.h +++ b/be/src/common/config.h @@ -799,8 +799,6 @@ DECLARE_mDouble(tablet_version_graph_orphan_vertex_ratio); // share delta writers when memtable_on_sink_node = true DECLARE_Bool(share_delta_writers); -// number of brpc stream per load -DECLARE_Int32(num_streams_per_load); // timeout for open load stream rpc in ms DECLARE_Int64(open_load_stream_timeout_ms); diff --git a/be/src/pipeline/pipeline_fragment_context.cpp b/be/src/pipeline/pipeline_fragment_context.cpp index 67d0e6045b82be..62bc3ca8decc06 100644 --- a/be/src/pipeline/pipeline_fragment_context.cpp +++ b/be/src/pipeline/pipeline_fragment_context.cpp @@ -318,6 +318,8 @@ Status PipelineFragmentContext::prepare(const doris::TPipelineFragmentParams& re _runtime_state->set_per_fragment_instance_idx(local_params.sender_id); _runtime_state->set_num_per_fragment_instances(request.num_senders); + _runtime_state->set_load_stream_per_node(request.load_stream_per_node); + _runtime_state->set_total_load_streams(request.total_load_streams); if (request.fragment.__isset.output_sink) { RETURN_IF_ERROR_OR_CATCH_EXCEPTION(DataSink::create_data_sink( diff --git a/be/src/pipeline/pipeline_x/pipeline_x_fragment_context.cpp b/be/src/pipeline/pipeline_x/pipeline_x_fragment_context.cpp index 95cdf47bec5424..fee49621f0ee15 100644 --- a/be/src/pipeline/pipeline_x/pipeline_x_fragment_context.cpp +++ b/be/src/pipeline/pipeline_x/pipeline_x_fragment_context.cpp @@ -211,6 +211,8 @@ Status PipelineXFragmentContext::prepare(const doris::TPipelineFragmentParams& r } _runtime_state->set_desc_tbl(_desc_tbl); _runtime_state->set_num_per_fragment_instances(request.num_senders); + _runtime_state->set_load_stream_per_node(request.load_stream_per_node); + _runtime_state->set_total_load_streams(request.total_load_streams); // 2. Build pipelines with operators in this fragment. auto root_pipeline = add_pipeline(); diff --git a/be/src/runtime/load_stream.cpp b/be/src/runtime/load_stream.cpp index b9cc5891b489c4..6f66e7239d651e 100644 --- a/be/src/runtime/load_stream.cpp +++ b/be/src/runtime/load_stream.cpp @@ -30,6 +30,7 @@ #include "runtime/load_channel.h" #include "runtime/load_stream_mgr.h" #include "runtime/load_stream_writer.h" +#include "util/runtime_profile.h" #include "util/thrift_util.h" #include "util/uid_util.h" @@ -251,6 +252,8 @@ LoadStream::~LoadStream() { Status LoadStream::init(const POpenLoadStreamRequest* request) { _txn_id = request->txn_id(); + _total_streams = request->total_streams(); + DCHECK(_total_streams > 0) << "total streams should be greator than 0"; _schema = std::make_shared(); RETURN_IF_ERROR(_schema->init(request->schema())); @@ -265,41 +268,49 @@ Status LoadStream::init(const POpenLoadStreamRequest* request) { Status LoadStream::close(int64_t src_id, const std::vector& tablets_to_commit, std::vector* success_tablet_ids, std::vector* failed_tablet_ids) { - std::lock_guard lock_guard(_lock); + std::lock_guard lock_guard(_lock); SCOPED_TIMER(_close_wait_timer); // we do nothing until recv CLOSE_LOAD from all stream to ensure all data are handled before ack _open_streams[src_id]--; - LOG(INFO) << "received CLOSE_LOAD from sender " << src_id << ", remaining " - << _open_streams[src_id] << " streams"; if (_open_streams[src_id] == 0) { _open_streams.erase(src_id); } + _close_load_cnt++; + LOG(INFO) << "received CLOSE_LOAD from sender " << src_id << ", remaining " + << _total_streams - _close_load_cnt << " senders"; + + _tablets_to_commit.insert(_tablets_to_commit.end(), tablets_to_commit.begin(), + tablets_to_commit.end()); + + if (_close_load_cnt < _total_streams) { + // do not return commit info if there is remaining streams. + return Status::OK(); + } Status st = Status::OK(); - if (_open_streams.size() == 0) { + { bthread::Mutex mutex; std::unique_lock lock(mutex); bthread::ConditionVariable cond; - bool ret = _load_stream_mgr->heavy_work_pool()->try_offer([this, &success_tablet_ids, - &failed_tablet_ids, - &tablets_to_commit, &mutex, - &cond, &st]() { - signal::set_signal_task_id(_load_id); - for (auto& it : _index_streams_map) { - st = it.second->close(tablets_to_commit, success_tablet_ids, failed_tablet_ids); - if (!st.ok()) { + bool ret = _load_stream_mgr->heavy_work_pool()->try_offer( + [this, &success_tablet_ids, &failed_tablet_ids, &mutex, &cond, &st]() { + signal::set_signal_task_id(_load_id); + for (auto& it : _index_streams_map) { + st = it.second->close(_tablets_to_commit, success_tablet_ids, + failed_tablet_ids); + if (!st.ok()) { + std::unique_lock lock(mutex); + cond.notify_one(); + return; + } + } + LOG(INFO) << "close load " << *this + << ", failed_tablet_num=" << failed_tablet_ids->size() + << ", success_tablet_num=" << success_tablet_ids->size(); std::unique_lock lock(mutex); cond.notify_one(); - return; - } - } - LOG(INFO) << "close load " << *this - << ", failed_tablet_num=" << failed_tablet_ids->size() - << ", success_tablet_num=" << success_tablet_ids->size(); - std::unique_lock lock(mutex); - cond.notify_one(); - }); + }); if (ret) { cond.wait(lock); } else { @@ -307,24 +318,21 @@ Status LoadStream::close(int64_t src_id, const std::vector& tablets_t "there is not enough thread resource for close load"); } } - - // do not return commit info for non-last one. return st; } -void LoadStream::_report_result(StreamId stream, Status& st, - std::vector* success_tablet_ids, - std::vector* failed_tablet_ids) { - LOG(INFO) << "report result, success tablet num " << success_tablet_ids->size() - << ", failed tablet num " << failed_tablet_ids->size(); +void LoadStream::_report_result(StreamId stream, const Status& st, + const std::vector& success_tablet_ids, + const std::vector& failed_tablet_ids) { + LOG(INFO) << "report result, success tablet num " << success_tablet_ids.size() + << ", failed tablet num " << failed_tablet_ids.size(); butil::IOBuf buf; PWriteStreamSinkResponse response; st.to_protobuf(response.mutable_status()); - for (auto& id : *success_tablet_ids) { + for (auto& id : success_tablet_ids) { response.add_success_tablet_ids(id); } - - for (auto& id : *failed_tablet_ids) { + for (auto& id : failed_tablet_ids) { response.add_failed_tablet_ids(id); } @@ -421,18 +429,20 @@ int LoadStream::on_received_messages(StreamId id, butil::IOBuf* const messages[] void LoadStream::_dispatch(StreamId id, const PStreamHeader& hdr, butil::IOBuf* data) { VLOG_DEBUG << PStreamHeader_Opcode_Name(hdr.opcode()) << " from " << hdr.src_id() << " with tablet " << hdr.tablet_id(); + if (UniqueId(hdr.load_id()) != UniqueId(_load_id)) { + Status st = Status::Error("invalid load id {}, expected {}", + UniqueId(hdr.load_id()).to_string(), + UniqueId(_load_id).to_string()); + _report_failure(id, st, hdr); + return; + } { std::lock_guard lock_guard(_lock); if (!_open_streams.contains(hdr.src_id())) { - std::vector success_tablet_ids; - std::vector failed_tablet_ids; - if (hdr.has_tablet_id()) { - failed_tablet_ids.push_back(hdr.tablet_id()); - } Status st = Status::Error("no open stream from source {}", hdr.src_id()); - _report_result(id, st, &success_tablet_ids, &failed_tablet_ids); + _report_failure(id, st, hdr); return; } } @@ -442,10 +452,7 @@ void LoadStream::_dispatch(StreamId id, const PStreamHeader& hdr, butil::IOBuf* case PStreamHeader::APPEND_DATA: { auto st = _append_data(hdr, data); if (!st.ok()) { - std::vector success_tablet_ids; - std::vector failed_tablet_ids; - failed_tablet_ids.push_back(hdr.tablet_id()); - _report_result(id, st, &success_tablet_ids, &failed_tablet_ids); + _report_failure(id, st, hdr); } } break; case PStreamHeader::CLOSE_LOAD: { @@ -454,7 +461,7 @@ void LoadStream::_dispatch(StreamId id, const PStreamHeader& hdr, butil::IOBuf* std::vector tablets_to_commit(hdr.tablets_to_commit().begin(), hdr.tablets_to_commit().end()); auto st = close(hdr.src_id(), tablets_to_commit, &success_tablet_ids, &failed_tablet_ids); - _report_result(id, st, &success_tablet_ids, &failed_tablet_ids); + _report_result(id, st, success_tablet_ids, failed_tablet_ids); brpc::StreamClose(id); } break; default: @@ -468,9 +475,9 @@ void LoadStream::on_idle_timeout(StreamId id) { } void LoadStream::on_closed(StreamId id) { - auto remaining_rpc_stream = remove_rpc_stream(); - LOG(INFO) << "stream closed " << id << ", remaining_rpc_stream=" << remaining_rpc_stream; - if (remaining_rpc_stream == 0) { + auto remaining_streams = _total_streams - _close_rpc_cnt.fetch_add(1) - 1; + LOG(INFO) << "stream " << id << " on_closed, remaining streams = " << remaining_streams; + if (remaining_streams == 0) { _load_stream_mgr->clear_load(_load_id); } } diff --git a/be/src/runtime/load_stream.h b/be/src/runtime/load_stream.h index fe7d90d502ec60..1c16c086e295b9 100644 --- a/be/src/runtime/load_stream.h +++ b/be/src/runtime/load_stream.h @@ -113,9 +113,6 @@ class LoadStream : public brpc::StreamInputHandler { _open_streams[src_id]++; } - uint32_t add_rpc_stream() { return ++_num_rpc_streams; } - uint32_t remove_rpc_stream() { return --_num_rpc_streams; } - Status close(int64_t src_id, const std::vector& tablets_to_commit, std::vector* success_tablet_ids, std::vector* failed_tablet_ids); @@ -130,16 +127,31 @@ class LoadStream : public brpc::StreamInputHandler { void _parse_header(butil::IOBuf* const message, PStreamHeader& hdr); void _dispatch(StreamId id, const PStreamHeader& hdr, butil::IOBuf* data); Status _append_data(const PStreamHeader& header, butil::IOBuf* data); - void _report_result(StreamId stream, Status& st, std::vector* success_tablet_ids, - std::vector* failed_tablet_ids); + + void _report_result(StreamId stream, const Status& st, + const std::vector& success_tablet_ids, + const std::vector& failed_tablet_ids); + + // report failure for one message + void _report_failure(StreamId stream, const Status& status, const PStreamHeader& header) { + std::vector success; // empty + std::vector failure; + if (header.has_tablet_id()) { + failure.push_back(header.tablet_id()); + } + _report_result(stream, status, success, failure); + } private: PUniqueId _load_id; std::unordered_map _index_streams_map; - std::atomic _num_rpc_streams; + int32_t _total_streams = 0; + int32_t _close_load_cnt = 0; + std::atomic _close_rpc_cnt = 0; + std::vector _tablets_to_commit; bthread::Mutex _lock; std::unordered_map _open_streams; - int64_t _txn_id; + int64_t _txn_id = 0; std::shared_ptr _schema; bool _enable_profile = false; std::unique_ptr _profile; diff --git a/be/src/runtime/plan_fragment_executor.cpp b/be/src/runtime/plan_fragment_executor.cpp index 9344378e91ea33..39277c1a42f610 100644 --- a/be/src/runtime/plan_fragment_executor.cpp +++ b/be/src/runtime/plan_fragment_executor.cpp @@ -224,6 +224,8 @@ Status PlanFragmentExecutor::prepare(const TExecPlanFragmentParams& request) { _runtime_state->set_per_fragment_instance_idx(params.sender_id); _runtime_state->set_num_per_fragment_instances(params.num_senders); + _runtime_state->set_load_stream_per_node(request.load_stream_per_node); + _runtime_state->set_total_load_streams(request.total_load_streams); // set up sink, if required if (request.fragment.__isset.output_sink) { diff --git a/be/src/runtime/runtime_state.h b/be/src/runtime/runtime_state.h index cba5142c154a1b..e990540d2f4fb2 100644 --- a/be/src/runtime/runtime_state.h +++ b/be/src/runtime/runtime_state.h @@ -309,6 +309,18 @@ class RuntimeState { int num_per_fragment_instances() const { return _num_per_fragment_instances; } + void set_load_stream_per_node(int load_stream_per_node) { + _load_stream_per_node = load_stream_per_node; + } + + int load_stream_per_node() const { return _load_stream_per_node; } + + void set_total_load_streams(int total_load_streams) { + _total_load_streams = total_load_streams; + } + + int total_load_streams() const { return _total_load_streams; } + bool disable_stream_preaggregations() const { return _query_options.disable_stream_preaggregations; } @@ -545,6 +557,8 @@ class RuntimeState { int _per_fragment_instance_idx; int _num_per_fragment_instances = 0; + int _load_stream_per_node = 0; + int _total_load_streams = 0; // The backend id on which this fragment instance runs int64_t _backend_id = -1; diff --git a/be/src/service/internal_service.cpp b/be/src/service/internal_service.cpp index 01151dcf340b99..d6846c07a16c74 100644 --- a/be/src/service/internal_service.cpp +++ b/be/src/service/internal_service.cpp @@ -401,7 +401,6 @@ void PInternalServiceImpl::open_load_stream(google::protobuf::RpcController* con return; } - load_stream->add_rpc_stream(); VLOG_DEBUG << "get streamid =" << streamid; st.to_protobuf(response->mutable_status()); }); diff --git a/be/src/vec/sink/load_stream_stub.cpp b/be/src/vec/sink/load_stream_stub.cpp index fe9887b3a3e00f..c2f7f246f30d60 100644 --- a/be/src/vec/sink/load_stream_stub.cpp +++ b/be/src/vec/sink/load_stream_stub.cpp @@ -102,11 +102,11 @@ LoadStreamStub::~LoadStreamStub() { } // open_load_stream -// tablets means Status LoadStreamStub::open(BrpcClientCache* client_cache, const NodeInfo& node_info, int64_t txn_id, const OlapTableSchemaParam& schema, - const std::vector& tablets_for_schema, bool enable_profile) { + const std::vector& tablets_for_schema, int total_streams, + bool enable_profile) { _num_open++; std::unique_lock lock(_mutex); if (_is_init.load()) { @@ -130,6 +130,7 @@ Status LoadStreamStub::open(BrpcClientCache* client_cache, request.set_src_id(_src_id); request.set_txn_id(txn_id); request.set_enable_profile(enable_profile); + request.set_total_streams(total_streams); schema.to_protobuf(request.mutable_schema()); for (auto& tablet : tablets_for_schema) { *request.add_tablets() = tablet; diff --git a/be/src/vec/sink/load_stream_stub.h b/be/src/vec/sink/load_stream_stub.h index 2db9ffcd95057f..3650b2aeae2188 100644 --- a/be/src/vec/sink/load_stream_stub.h +++ b/be/src/vec/sink/load_stream_stub.h @@ -148,7 +148,8 @@ class LoadStreamStub { // open_load_stream Status open(BrpcClientCache* client_cache, const NodeInfo& node_info, int64_t txn_id, const OlapTableSchemaParam& schema, - const std::vector& tablets_for_schema, bool enable_profile); + const std::vector& tablets_for_schema, int total_streams, + bool enable_profile); // for mock this class in UT #ifdef BE_TEST diff --git a/be/src/vec/sink/load_stream_stub_pool.cpp b/be/src/vec/sink/load_stream_stub_pool.cpp index 834c152386520c..5848ca5a51aed9 100644 --- a/be/src/vec/sink/load_stream_stub_pool.cpp +++ b/be/src/vec/sink/load_stream_stub_pool.cpp @@ -28,14 +28,14 @@ LoadStreamStubPool::LoadStreamStubPool() = default; LoadStreamStubPool::~LoadStreamStubPool() = default; std::shared_ptr LoadStreamStubPool::get_or_create(PUniqueId load_id, int64_t src_id, - int64_t dst_id) { + int64_t dst_id, int num_streams) { auto key = std::make_pair(UniqueId(load_id), dst_id); std::lock_guard lock(_mutex); std::shared_ptr streams = _pool[key].lock(); if (streams) { return streams; } - int32_t num_streams = std::max(1, config::num_streams_per_load); + DCHECK(num_streams > 0) << "stream num should be greater than 0"; auto [it, _] = _template_stubs.emplace(load_id, new LoadStreamStub {load_id, src_id}); auto deleter = [this, key](Streams* s) { std::lock_guard lock(_mutex); diff --git a/be/src/vec/sink/load_stream_stub_pool.h b/be/src/vec/sink/load_stream_stub_pool.h index ae550340d25a00..73b41fdd61adc8 100644 --- a/be/src/vec/sink/load_stream_stub_pool.h +++ b/be/src/vec/sink/load_stream_stub_pool.h @@ -78,7 +78,8 @@ class LoadStreamStubPool { ~LoadStreamStubPool(); - std::shared_ptr get_or_create(PUniqueId load_id, int64_t src_id, int64_t dst_id); + std::shared_ptr get_or_create(PUniqueId load_id, int64_t src_id, int64_t dst_id, + int num_streams); size_t size() { std::lock_guard lock(_mutex); diff --git a/be/src/vec/sink/vtablet_sink_v2.cpp b/be/src/vec/sink/vtablet_sink_v2.cpp index 69a372e0e3886f..6e610ee717af41 100644 --- a/be/src/vec/sink/vtablet_sink_v2.cpp +++ b/be/src/vec/sink/vtablet_sink_v2.cpp @@ -152,6 +152,12 @@ Status VOlapTableSinkV2::prepare(RuntimeState* state) { _sender_id = state->per_fragment_instance_idx(); _num_senders = state->num_per_fragment_instances(); + _stream_per_node = state->load_stream_per_node(); + _total_streams = state->total_load_streams(); + DCHECK(_stream_per_node > 0) << "load stream per node should be greator than 0"; + DCHECK(_total_streams > 0) << "total load streams should be greator than 0"; + LOG(INFO) << "num senders: " << _num_senders << ", stream per node: " << _stream_per_node + << ", total_streams " << _total_streams; _is_high_priority = (state->execution_timeout() <= config::load_task_high_priority_threshold_second); @@ -218,19 +224,19 @@ Status VOlapTableSinkV2::_open_streams(int64_t src_id) { return Status::InternalError("Unknown node {} in tablet location", dst_id); } std::shared_ptr streams; - streams = ExecEnv::GetInstance()->load_stream_stub_pool()->get_or_create(_load_id, src_id, - dst_id); + streams = ExecEnv::GetInstance()->load_stream_stub_pool()->get_or_create( + _load_id, src_id, dst_id, _stream_per_node); // get tablet schema from each backend only in the 1st stream for (auto& stream : *streams | std::ranges::views::take(1)) { const std::vector& tablets_for_schema = _indexes_from_node[node_info->id]; RETURN_IF_ERROR(stream->open(_state->exec_env()->brpc_internal_client_cache(), *node_info, _txn_id, *_schema, tablets_for_schema, - _state->enable_profile())); + _total_streams, _state->enable_profile())); } // for the rest streams, open without getting tablet schema for (auto& stream : *streams | std::ranges::views::drop(1)) { RETURN_IF_ERROR(stream->open(_state->exec_env()->brpc_internal_client_cache(), - *node_info, _txn_id, *_schema, {}, + *node_info, _txn_id, *_schema, {}, _total_streams, _state->enable_profile())); } _streams_for_node[dst_id] = streams; @@ -293,7 +299,7 @@ Status VOlapTableSinkV2::_select_streams(int64_t tablet_id, Streams& streams) { for (auto& node_id : location->node_ids) { streams.emplace_back(_streams_for_node[node_id]->at(_stream_index)); } - _stream_index = (_stream_index + 1) % config::num_streams_per_load; + _stream_index = (_stream_index + 1) % _stream_per_node; return Status::OK(); } diff --git a/be/src/vec/sink/vtablet_sink_v2.h b/be/src/vec/sink/vtablet_sink_v2.h index a67c4e65cd2cae..1a67ea581ec6e5 100644 --- a/be/src/vec/sink/vtablet_sink_v2.h +++ b/be/src/vec/sink/vtablet_sink_v2.h @@ -155,6 +155,8 @@ class VOlapTableSinkV2 final : public DataSink { // To support multiple senders, we maintain a channel for each sender. int _sender_id = -1; int _num_senders = -1; + int _stream_per_node = 0; + int _total_streams = 0; bool _is_high_priority = false; bool _write_file_cache = false; diff --git a/be/test/runtime/load_stream_test.cpp b/be/test/runtime/load_stream_test.cpp index bdd0ace9a8b97c..05dfa2ee1a8146 100644 --- a/be/test/runtime/load_stream_test.cpp +++ b/be/test/runtime/load_stream_test.cpp @@ -67,6 +67,7 @@ const uint32_t ABNORMAL_SENDER_ID = 10000; const int64_t NORMAL_TXN_ID = 600001; const UniqueId NORMAL_LOAD_ID(1, 1); const UniqueId ABNORMAL_LOAD_ID(1, 0); +std::string NORMAL_STRING("normal"); std::string ABNORMAL_STRING("abnormal"); void construct_schema(OlapTableSchemaParam* schema) { @@ -374,6 +375,8 @@ class LoadStreamMgrTest : public testing::Test { } LoadStreamSharedPtr load_stream; + LOG(INFO) << "total streams: " << request->total_streams(); + EXPECT_GT(request->total_streams(), 0); auto st = _load_stream_mgr->open_load_stream(request, load_stream); stream_options.handler = load_stream.get(); @@ -387,8 +390,6 @@ class LoadStreamMgrTest : public testing::Test { return; } - load_stream->add_rpc_stream(); - status->set_status_code(TStatusCode::OK); response->set_allocated_status(status.get()); static_cast(response->release_status()); @@ -417,7 +418,7 @@ class LoadStreamMgrTest : public testing::Test { std::function _cb; }; - Status connect_stream(int64_t sender_id = NORMAL_SENDER_ID) { + Status connect_stream(int64_t sender_id = NORMAL_SENDER_ID, int total_streams = 1) { brpc::Channel channel; std::cerr << "connect_stream" << std::endl; // Initialize the channel, NULL means using default options. @@ -450,6 +451,7 @@ class LoadStreamMgrTest : public testing::Test { *request.mutable_load_id() = id; request.set_txn_id(NORMAL_TXN_ID); request.set_src_id(sender_id); + request.set_total_streams(total_streams); auto ptablet = request.add_tablets(); ptablet->set_tablet_id(NORMAL_TABLET_ID); ptablet->set_index_id(NORMAL_INDEX_ID); @@ -491,7 +493,7 @@ class LoadStreamMgrTest : public testing::Test { : _heavy_work_pool(4, 32, "load_stream_test_heavy"), _light_work_pool(4, 32, "load_stream_test_light") {} - void close_load(MockSinkClient& client, uint32_t sender_id) { + void close_load(MockSinkClient& client, uint32_t sender_id = NORMAL_SENDER_ID) { butil::IOBuf append_buf; PStreamHeader header; header.mutable_load_id()->set_hi(1); @@ -535,6 +537,11 @@ class LoadStreamMgrTest : public testing::Test { static_cast(client.send(&append_buf)); } + void write_normal(MockSinkClient& client) { + write_one_tablet(client, NORMAL_LOAD_ID, NORMAL_SENDER_ID, NORMAL_INDEX_ID, + NORMAL_TABLET_ID, 0, NORMAL_STRING, true); + } + void write_abnormal_load(MockSinkClient& client) { write_one_tablet(client, ABNORMAL_LOAD_ID, NORMAL_SENDER_ID, NORMAL_INDEX_ID, NORMAL_TABLET_ID, 0, ABNORMAL_STRING, true); @@ -657,25 +664,52 @@ class LoadStreamMgrTest : public testing::Test { // // one client -TEST_F(LoadStreamMgrTest, one_client_abnormal_load) { +TEST_F(LoadStreamMgrTest, one_client_normal) { MockSinkClient client; auto st = client.connect_stream(); EXPECT_TRUE(st.ok()); - write_abnormal_load(client); - // TODO check abnormal load id + write_normal(client); reset_response_stat(); - close_load(client, 1); + close_load(client, ABNORMAL_SENDER_ID); wait_for_ack(1); EXPECT_EQ(g_response_stat.num, 1); EXPECT_EQ(g_response_stat.success_tablet_ids.size(), 0); + EXPECT_EQ(g_response_stat.failed_tablet_ids.size(), 0); EXPECT_EQ(_load_stream_mgr->get_load_stream_num(), 1); - close_load(client, 0); + close_load(client); wait_for_ack(2); EXPECT_EQ(g_response_stat.num, 2); EXPECT_EQ(g_response_stat.success_tablet_ids.size(), 1); + EXPECT_EQ(g_response_stat.failed_tablet_ids.size(), 0); + EXPECT_EQ(g_response_stat.success_tablet_ids[0], NORMAL_TABLET_ID); + + // server will close stream on CLOSE_LOAD + wait_for_close(); + EXPECT_EQ(_load_stream_mgr->get_load_stream_num(), 0); +} + +TEST_F(LoadStreamMgrTest, one_client_abnormal_load) { + MockSinkClient client; + auto st = client.connect_stream(); + EXPECT_TRUE(st.ok()); + + reset_response_stat(); + write_abnormal_load(client); + wait_for_ack(1); + EXPECT_EQ(g_response_stat.num, 1); + EXPECT_EQ(g_response_stat.success_tablet_ids.size(), 0); + EXPECT_EQ(g_response_stat.failed_tablet_ids.size(), 1); + EXPECT_EQ(g_response_stat.failed_tablet_ids[0], NORMAL_TABLET_ID); + EXPECT_EQ(_load_stream_mgr->get_load_stream_num(), 1); + + close_load(client); + wait_for_ack(2); + EXPECT_EQ(g_response_stat.num, 2); + EXPECT_EQ(g_response_stat.success_tablet_ids.size(), 0); + EXPECT_EQ(g_response_stat.failed_tablet_ids.size(), 1); EXPECT_EQ(g_response_stat.success_tablet_ids[0], NORMAL_TABLET_ID); // server will close stream on CLOSE_LOAD @@ -1063,7 +1097,7 @@ TEST_F(LoadStreamMgrTest, two_client_one_index_one_tablet_three_segment) { MockSinkClient clients[2]; for (int i = 0; i < 2; i++) { - auto st = clients[i].connect_stream(NORMAL_SENDER_ID + i); + auto st = clients[i].connect_stream(NORMAL_SENDER_ID + i, 2); EXPECT_TRUE(st.ok()); } reset_response_stat(); @@ -1132,4 +1166,77 @@ TEST_F(LoadStreamMgrTest, two_client_one_index_one_tablet_three_segment) { EXPECT_EQ(_load_stream_mgr->get_load_stream_num(), 0); } +TEST_F(LoadStreamMgrTest, two_client_one_close_before_the_other_open) { + MockSinkClient clients[2]; + + EXPECT_TRUE(clients[0].connect_stream(NORMAL_SENDER_ID, 2).ok()); + + reset_response_stat(); + + std::vector segment_data; + segment_data.resize(6); + for (int32_t segid = 2; segid >= 0; segid--) { + for (int i = 0; i < 2; i++) { + std::string data = "sender_id=" + std::to_string(i) + ",segid=" + std::to_string(segid); + segment_data[i * 3 + segid] = data; + LOG(INFO) << "segment_data[" << i * 3 + segid << "]" << data; + } + } + + for (int32_t segid = 2; segid >= 0; segid--) { + int i = 0; + write_one_tablet(clients[i], NORMAL_LOAD_ID, NORMAL_SENDER_ID + i, NORMAL_INDEX_ID, + NORMAL_TABLET_ID, segid, segment_data[i * 3 + segid], true); + } + + EXPECT_EQ(g_response_stat.num, 0); + // CLOSE_LOAD + close_load(clients[0], 0); + wait_for_ack(1); + EXPECT_EQ(g_response_stat.num, 1); + EXPECT_EQ(g_response_stat.success_tablet_ids.size(), 0); + EXPECT_EQ(g_response_stat.failed_tablet_ids.size(), 0); + + // sender 0 closed, before open sender 1, load stream should still be open + EXPECT_EQ(_load_stream_mgr->get_load_stream_num(), 1); + + EXPECT_TRUE(clients[1].connect_stream(NORMAL_SENDER_ID + 1, 2).ok()); + + for (int32_t segid = 2; segid >= 0; segid--) { + int i = 1; + write_one_tablet(clients[i], NORMAL_LOAD_ID, NORMAL_SENDER_ID + i, NORMAL_INDEX_ID, + NORMAL_TABLET_ID, segid, segment_data[i * 3 + segid], true); + } + + close_load(clients[1], 1); + wait_for_ack(2); + EXPECT_EQ(g_response_stat.num, 2); + EXPECT_EQ(g_response_stat.success_tablet_ids.size(), 1); + EXPECT_EQ(g_response_stat.failed_tablet_ids.size(), 0); + EXPECT_EQ(g_response_stat.success_tablet_ids[0], NORMAL_TABLET_ID); + + // server will close stream on CLOSE_LOAD + wait_for_close(); + EXPECT_EQ(_load_stream_mgr->get_load_stream_num(), 0); + + auto written_data = read_data(NORMAL_TXN_ID, NORMAL_PARTITION_ID, NORMAL_TABLET_ID, 0); + size_t sender_pos = written_data.find('='); + size_t sender_end = written_data.find(','); + EXPECT_NE(sender_pos, std::string::npos); + EXPECT_NE(sender_end, std::string::npos); + auto sender_str = written_data.substr(sender_pos + 1, sender_end - sender_pos); + LOG(INFO) << "sender_str " << sender_str; + uint32_t sender_id = std::stoi(sender_str); + + for (int i = 0; i < 3; i++) { + auto written_data = read_data(NORMAL_TXN_ID, NORMAL_PARTITION_ID, NORMAL_TABLET_ID, i); + EXPECT_EQ(written_data, segment_data[sender_id * 3 + i]); + } + sender_id = (sender_id + 1) % 2; + for (int i = 0; i < 3; i++) { + auto written_data = read_data(NORMAL_TXN_ID, NORMAL_PARTITION_ID, NORMAL_TABLET_ID, i + 3); + EXPECT_EQ(written_data, segment_data[sender_id * 3 + i]); + } +} + } // namespace doris diff --git a/be/test/vec/exec/load_stream_stub_pool_test.cpp b/be/test/vec/exec/load_stream_stub_pool_test.cpp index f1ccb70beeb80b..929b906aab7d66 100644 --- a/be/test/vec/exec/load_stream_stub_pool_test.cpp +++ b/be/test/vec/exec/load_stream_stub_pool_test.cpp @@ -36,9 +36,9 @@ TEST_F(LoadStreamStubPoolTest, test) { PUniqueId load_id; load_id.set_hi(1); load_id.set_hi(2); - auto streams1 = pool.get_or_create(load_id, src_id, 101); - auto streams2 = pool.get_or_create(load_id, src_id, 102); - auto streams3 = pool.get_or_create(load_id, src_id, 101); + auto streams1 = pool.get_or_create(load_id, src_id, 101, 5); + auto streams2 = pool.get_or_create(load_id, src_id, 102, 5); + auto streams3 = pool.get_or_create(load_id, src_id, 101, 5); EXPECT_EQ(2, pool.size()); EXPECT_EQ(1, pool.templates_size()); EXPECT_EQ(streams1, streams3); diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/StreamLoadPlanner.java b/fe/fe-core/src/main/java/org/apache/doris/planner/StreamLoadPlanner.java index 934bca7ac0c3b5..f4131235da359c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/StreamLoadPlanner.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/StreamLoadPlanner.java @@ -298,6 +298,8 @@ public TExecPlanFragmentParams plan(TUniqueId loadId, int fragmentInstanceIdInde perNodeScanRange.put(scanNode.getId().asInt(), scanRangeParams); execParams.setPerNodeScanRanges(perNodeScanRange); params.setParams(execParams); + params.setLoadStreamPerNode(taskInfo.getStreamPerNode()); + params.setTotalLoadStreams(taskInfo.getStreamPerNode()); TQueryOptions queryOptions = new TQueryOptions(); queryOptions.setQueryType(TQueryType.LOAD); queryOptions.setQueryTimeout(timeout); @@ -499,6 +501,8 @@ public TPipelineFragmentParams planForPipeline(TUniqueId loadId, int fragmentIns pipParams.per_exch_num_senders = Maps.newHashMap(); pipParams.destinations = Lists.newArrayList(); pipParams.setNumSenders(1); + pipParams.setLoadStreamPerNode(taskInfo.getStreamPerNode()); + pipParams.setTotalLoadStreams(taskInfo.getStreamPerNode()); TPipelineInstanceParams localParams = new TPipelineInstanceParams(); localParams.setFragmentInstanceId(new TUniqueId(loadId.hi, loadId.lo + fragmentInstanceIdIndex)); diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java index 9aaca2f8e2cdbb..56ca362e69b132 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java @@ -78,6 +78,7 @@ import org.apache.doris.task.LoadEtlTask; import org.apache.doris.thrift.PaloInternalServiceVersion; import org.apache.doris.thrift.TBrokerScanRange; +import org.apache.doris.thrift.TDataSinkType; import org.apache.doris.thrift.TDescriptorTable; import org.apache.doris.thrift.TDetailedReportParams; import org.apache.doris.thrift.TErrorTabletInfo; @@ -688,6 +689,7 @@ private void sendFragment() throws TException, RpcException, UserException { int backendIdx = 0; int profileFragmentId = 0; long memoryLimit = queryOptions.getMemLimit(); + Set backendsWithOlapTableSink = Sets.newHashSet(); beToExecStates.clear(); // If #fragments >=2, use twoPhaseExecution with exec_plan_fragments_prepare and exec_plan_fragments_start, // else use exec_plan_fragments directly. @@ -755,8 +757,23 @@ private void sendFragment() throws TException, RpcException, UserException { beToExecStates.putIfAbsent(execState.backend.getId(), states); } states.addState(execState); + if (tParam.getFragment().getOutputSink() != null + && tParam.getFragment().getOutputSink().getType() == TDataSinkType.OLAP_TABLE_SINK) { + backendsWithOlapTableSink.add(execState.backend.getId()); + } ++backendIdx; } + int loadStreamPerNode = 1; + if (ConnectContext.get() != null && ConnectContext.get().getSessionVariable() != null) { + loadStreamPerNode = ConnectContext.get().getSessionVariable().getLoadStreamPerNode(); + } + for (TExecPlanFragmentParams tParam : tParams) { + if (tParam.getFragment().getOutputSink() != null + && tParam.getFragment().getOutputSink().getType() == TDataSinkType.OLAP_TABLE_SINK) { + tParam.setLoadStreamPerNode(loadStreamPerNode); + tParam.setTotalLoadStreams(backendsWithOlapTableSink.size() * loadStreamPerNode); + } + } profileFragmentId += 1; } // end for fragments @@ -845,6 +862,7 @@ private void sendPipelineCtx() throws TException, RpcException, UserException { } } + Set backendsWithOlapTableSink = Sets.newHashSet(); // 3. group PipelineExecContext by BE. // So that we can use one RPC to send all fragment instances of a BE. for (Map.Entry entry : tParams.entrySet()) { @@ -878,8 +896,25 @@ private void sendPipelineCtx() throws TException, RpcException, UserException { } ctxs.addContext(pipelineExecContext); + if (entry.getValue().getFragment().getOutputSink() != null + && entry.getValue().getFragment().getOutputSink().getType() + == TDataSinkType.OLAP_TABLE_SINK) { + backendsWithOlapTableSink.add(backendId); + } ++backendIdx; } + int loadStreamPerNode = 1; + if (ConnectContext.get() != null && ConnectContext.get().getSessionVariable() != null) { + loadStreamPerNode = ConnectContext.get().getSessionVariable().getLoadStreamPerNode(); + } + for (Map.Entry entry : tParams.entrySet()) { + if (entry.getValue().getFragment().getOutputSink() != null + && entry.getValue().getFragment().getOutputSink().getType() + == TDataSinkType.OLAP_TABLE_SINK) { + entry.getValue().setLoadStreamPerNode(loadStreamPerNode); + entry.getValue().setTotalLoadStreams(backendsWithOlapTableSink.size() * loadStreamPerNode); + } + } profileFragmentId += 1; } // end for fragments diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java index 369805700399ab..955450a15c4452 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java @@ -411,6 +411,8 @@ public class SessionVariable implements Serializable, Writable { public static final String ENABLE_MEMTABLE_ON_SINK_NODE = "enable_memtable_on_sink_node"; + public static final String LOAD_STREAM_PER_NODE = "load_stream_per_node"; + public static final String ENABLE_UNIQUE_KEY_PARTIAL_UPDATE = "enable_unique_key_partial_update"; public static final String INVERTED_INDEX_CONJUNCTION_OPT_THRESHOLD = "inverted_index_conjunction_opt_threshold"; @@ -1236,6 +1238,9 @@ public void setMaxJoinNumberOfReorder(int maxJoinNumberOfReorder) { @VariableMgr.VarAttr(name = ENABLE_MEMTABLE_ON_SINK_NODE, needForward = true) public boolean enableMemtableOnSinkNode = false; + @VariableMgr.VarAttr(name = LOAD_STREAM_PER_NODE) + public int loadStreamPerNode = 20; + @VariableMgr.VarAttr(name = ENABLE_INSERT_GROUP_COMMIT) public boolean enableInsertGroupCommit = false; @@ -2405,6 +2410,14 @@ public void setEnableUniqueKeyPartialUpdate(boolean enableUniqueKeyPartialUpdate this.enableUniqueKeyPartialUpdate = enableUniqueKeyPartialUpdate; } + public int getLoadStreamPerNode() { + return loadStreamPerNode; + } + + public void setLoadStreamPerNode(int loadStreamPerNode) { + this.loadStreamPerNode = loadStreamPerNode; + } + /** * Serialize to thrift object. * Used for rest api. diff --git a/fe/fe-core/src/main/java/org/apache/doris/task/LoadTaskInfo.java b/fe/fe-core/src/main/java/org/apache/doris/task/LoadTaskInfo.java index 3174e4d5c6b6a1..610e243cd9285d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/task/LoadTaskInfo.java +++ b/fe/fe-core/src/main/java/org/apache/doris/task/LoadTaskInfo.java @@ -125,6 +125,10 @@ default boolean isMemtableOnSinkNode() { return false; } + default int getStreamPerNode() { + return 20; + } + class ImportColumnDescs { public List descs = Lists.newArrayList(); public boolean isColumnDescsRewrited = false; diff --git a/fe/fe-core/src/main/java/org/apache/doris/task/StreamLoadTask.java b/fe/fe-core/src/main/java/org/apache/doris/task/StreamLoadTask.java index 485a3599b38f7f..53a47d385b5b67 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/task/StreamLoadTask.java +++ b/fe/fe-core/src/main/java/org/apache/doris/task/StreamLoadTask.java @@ -89,6 +89,7 @@ public class StreamLoadTask implements LoadTaskInfo { private boolean enableProfile = false; private boolean memtableOnSinkNode = false; + private int streamPerNode = 20; private byte enclose = 0; @@ -309,6 +310,15 @@ public void setMemtableOnSinkNode(boolean memtableOnSinkNode) { this.memtableOnSinkNode = memtableOnSinkNode; } + @Override + public int getStreamPerNode() { + return streamPerNode; + } + + public void setStreamPerNode(int streamPerNode) { + this.streamPerNode = streamPerNode; + } + public static StreamLoadTask fromTStreamLoadPutRequest(TStreamLoadPutRequest request) throws UserException { StreamLoadTask streamLoadTask = new StreamLoadTask(request.getLoadId(), request.getTxnId(), request.getFileType(), request.getFormatType(), @@ -447,6 +457,9 @@ private void setOptionalFromTSLPutRequest(TStreamLoadPutRequest request) throws if (request.isSetMemtableOnSinkNode()) { this.memtableOnSinkNode = request.isMemtableOnSinkNode(); } + if (request.isSetStreamPerNode()) { + this.streamPerNode = request.getStreamPerNode(); + } } // used for stream load diff --git a/gensrc/proto/internal_service.proto b/gensrc/proto/internal_service.proto index 9a36916317f70d..f9c2603cb985c9 100644 --- a/gensrc/proto/internal_service.proto +++ b/gensrc/proto/internal_service.proto @@ -749,6 +749,7 @@ message POpenLoadStreamRequest { optional POlapTableSchemaParam schema = 4; repeated PTabletID tablets = 5; optional bool enable_profile = 6 [default = false]; + optional int64 total_streams = 7; } message PTabletSchemaWithIndex { diff --git a/gensrc/thrift/FrontendService.thrift b/gensrc/thrift/FrontendService.thrift index 1e0ad2d4624998..04eaa5782412c5 100644 --- a/gensrc/thrift/FrontendService.thrift +++ b/gensrc/thrift/FrontendService.thrift @@ -641,6 +641,7 @@ struct TStreamLoadPutRequest { 52: optional i8 escape 53: optional bool memtable_on_sink_node; 54: optional bool group_commit + 55: optional i32 stream_per_node; } struct TStreamLoadPutResult { diff --git a/gensrc/thrift/PaloInternalService.thrift b/gensrc/thrift/PaloInternalService.thrift index cf38f51c054cde..e55ab89e3285fb 100644 --- a/gensrc/thrift/PaloInternalService.thrift +++ b/gensrc/thrift/PaloInternalService.thrift @@ -455,6 +455,12 @@ struct TExecPlanFragmentParams { 24: optional map file_scan_params 25: optional i64 wal_id + + // num load stream for each sink backend + 26: optional i32 load_stream_per_node + + // total num of load streams the downstream backend will see + 27: optional i32 total_load_streams } struct TExecPlanFragmentParamsList { @@ -670,6 +676,8 @@ struct TPipelineFragmentParams { // scan node id -> scan range params, only for external file scan 29: optional map file_scan_params 30: optional bool group_commit = false; + 31: optional i32 load_stream_per_node // num load stream for each sink backend + 32: optional i32 total_load_streams // total num of load streams the downstream backend will see } struct TPipelineFragmentParamsList { From 96d2e3394a23fd115f706b38fa5b851787b85c05 Mon Sep 17 00:00:00 2001 From: seawinde <149132972+seawinde@users.noreply.github.com> Date: Wed, 8 Nov 2023 17:14:15 +0800 Subject: [PATCH 48/88] [opt](meta) Improve the performance of getting expr name (#26341) CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, name) It's time-consuming when call many times. So lazy call when necessary --- .../java/org/apache/doris/analysis/AnalyticExpr.java | 8 ++++++-- .../java/org/apache/doris/analysis/ColumnRefExpr.java | 9 +++++++-- .../src/main/java/org/apache/doris/analysis/Expr.java | 10 +++++++--- .../org/apache/doris/analysis/FunctionCallExpr.java | 7 +++++-- .../java/org/apache/doris/analysis/LiteralExpr.java | 8 ++++++-- .../main/java/org/apache/doris/analysis/SlotRef.java | 8 ++++++-- .../java/org/apache/doris/analysis/VirtualSlotRef.java | 2 +- .../apache/doris/nereids/analyzer/UnboundFunction.java | 6 +++++- .../nereids/trees/expressions/AggregateExpression.java | 6 +++++- .../trees/expressions/AssertNumRowsElement.java | 6 +++++- .../doris/nereids/trees/expressions/Expression.java | 8 ++++++-- .../nereids/trees/expressions/NamedExpression.java | 6 +++++- .../doris/nereids/trees/expressions/SubqueryExpr.java | 5 ++++- .../trees/expressions/functions/BoundFunction.java | 6 +++++- .../nereids/trees/expressions/literal/Literal.java | 6 +++++- 15 files changed, 78 insertions(+), 23 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyticExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyticExpr.java index 37b4684f1569c0..39c428f7fa503b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyticExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/AnalyticExpr.java @@ -44,6 +44,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Objects; +import java.util.Optional; /** * Representation of an analytic function call with OVER clause. @@ -147,8 +148,11 @@ public AnalyticWindow getWindow() { } @Override - protected String getExprName() { - return Utils.normalizeName(getFnCall().getExprName(), DEFAULT_EXPR_NAME); + public String getExprName() { + if (!this.exprName.isPresent()) { + this.exprName = Optional.of(Utils.normalizeName(getFnCall().getExprName(), DEFAULT_EXPR_NAME)); + } + return this.exprName.get(); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnRefExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnRefExpr.java index d980a6707602bf..5a47ab69402e30 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnRefExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/ColumnRefExpr.java @@ -26,6 +26,8 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import java.util.Optional; + public class ColumnRefExpr extends Expr { private static final Logger LOG = LogManager.getLogger(ColumnRefExpr.class); private String columnName; @@ -55,8 +57,11 @@ public String getName() { } @Override - protected String getExprName() { - return Utils.normalizeName(getName(), DEFAULT_EXPR_NAME); + public String getExprName() { + if (!this.exprName.isPresent()) { + this.exprName = Optional.of(Utils.normalizeName(getName(), DEFAULT_EXPR_NAME)); + } + return this.exprName.get(); } public void setName(String name) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java index 5b7479ae2d41b6..09848e3d186d1a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/Expr.java @@ -69,6 +69,7 @@ import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Optional; import java.util.Set; /** @@ -296,7 +297,7 @@ public boolean apply(Expr arg) { // Flag to indicate whether to wrap this expr's toSql() in parenthesis. Set by parser. // Needed for properly capturing expr precedences in the SQL string. protected boolean printSqlInParens = false; - protected final String exprName = Utils.normalizeName(this.getClass().getSimpleName(), DEFAULT_EXPR_NAME); + protected Optional exprName = Optional.empty(); protected Expr() { super(); @@ -340,8 +341,11 @@ public void setId(ExprId id) { // Name of expr, this is used by generating column name automatically when there is no // alias or is not slotRef - protected String getExprName() { - return this.exprName; + public String getExprName() { + if (!this.exprName.isPresent()) { + this.exprName = Optional.of(Utils.normalizeName(this.getClass().getSimpleName(), DEFAULT_EXPR_NAME)); + } + return this.exprName.get(); } public Type getType() { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java index 6fbb35aac6d325..12e471979d504c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/FunctionCallExpr.java @@ -313,8 +313,11 @@ private FunctionCallExpr() { } @Override - protected String getExprName() { - return Utils.normalizeName(this.getFnName().getFunction(), DEFAULT_EXPR_NAME); + public String getExprName() { + if (!this.exprName.isPresent()) { + this.exprName = Optional.of(Utils.normalizeName(this.getFnName().getFunction(), DEFAULT_EXPR_NAME)); + } + return this.exprName.get(); } public FunctionCallExpr(String functionName, List params) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/LiteralExpr.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/LiteralExpr.java index bbeffe7366d379..7047a8d900f245 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/LiteralExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/LiteralExpr.java @@ -36,6 +36,7 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.util.List; +import java.util.Optional; public abstract class LiteralExpr extends Expr implements Comparable { private static final Logger LOG = LogManager.getLogger(LiteralExpr.class); @@ -365,8 +366,11 @@ public static LiteralExpr getLiteralByMysqlType(int mysqlType) throws AnalysisEx } @Override - protected String getExprName() { - return "literal"; + public String getExprName() { + if (!this.exprName.isPresent()) { + this.exprName = Optional.of("literal"); + } + return this.exprName.get(); } // Port from mysql get_param_length diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/SlotRef.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/SlotRef.java index 9b664d8b42a60d..ec5221bf6ef7e2 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/SlotRef.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/SlotRef.java @@ -45,6 +45,7 @@ import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.TreeSet; @@ -307,8 +308,11 @@ public String toColumnLabel() { } @Override - protected String getExprName() { - return toColumnLabel(); + public String getExprName() { + if (!this.exprName.isPresent()) { + this.exprName = Optional.of(toColumnLabel()); + } + return this.exprName.get(); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/VirtualSlotRef.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/VirtualSlotRef.java index 07eba56652a159..60cf3577d728cc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/VirtualSlotRef.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/VirtualSlotRef.java @@ -123,7 +123,7 @@ public void analyzeImpl(Analyzer analyzer) throws AnalysisException { } @Override - protected String getExprName() { + public String getExprName() { return super.getExprName(); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundFunction.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundFunction.java index d73474906a9dd7..4934d8ddc4e00e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundFunction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/analyzer/UnboundFunction.java @@ -28,6 +28,7 @@ import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.stream.Collectors; /** @@ -63,7 +64,10 @@ public String getName() { @Override public String getExpressionName() { - return Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME); + if (!this.exprName.isPresent()) { + this.exprName = Optional.of(Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME)); + } + return this.exprName.get(); } public String getDbName() { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AggregateExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AggregateExpression.java index d097efd7aed488..2e20dd05180a71 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AggregateExpression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AggregateExpression.java @@ -30,6 +30,7 @@ import java.util.List; import java.util.Objects; +import java.util.Optional; /** * AggregateExpression. @@ -120,7 +121,10 @@ public String toString() { @Override public String getExpressionName() { - return Utils.normalizeName(function.getName(), DEFAULT_EXPRESSION_NAME); + if (!this.exprName.isPresent()) { + this.exprName = Optional.of(Utils.normalizeName(function.getName(), DEFAULT_EXPRESSION_NAME)); + } + return this.exprName.get(); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AssertNumRowsElement.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AssertNumRowsElement.java index 9b2261e73bcca5..a80baaf68dddbf 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AssertNumRowsElement.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/AssertNumRowsElement.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Objects; +import java.util.Optional; /** * Number of rows returned by inspection in subquery. @@ -89,7 +90,10 @@ public String toSql() { @Override public String getExpressionName() { - return assertion.name().toLowerCase(); + if (!this.exprName.isPresent()) { + this.exprName = Optional.of(Utils.normalizeName(assertion.name().toLowerCase(), DEFAULT_EXPRESSION_NAME)); + } + return this.exprName.get(); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java index 2a432aaa80b8c8..a10de9282b2377 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/Expression.java @@ -44,6 +44,7 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.Set; /** @@ -53,7 +54,7 @@ public abstract class Expression extends AbstractTreeNode implements public static final String DEFAULT_EXPRESSION_NAME = "expression"; // Mask this expression is generated by rule, should be removed. public boolean isGeneratedIsNotNull = false; - protected final String exprName = Utils.normalizeName(this.getClass().getSimpleName(), DEFAULT_EXPRESSION_NAME); + protected Optional exprName = Optional.empty(); private final int depth; private final int width; @@ -97,7 +98,10 @@ public Alias alias(String alias) { // Name of expr, this is used by generating column name automatically when there is no // alias public String getExpressionName() { - return this.exprName; + if (!this.exprName.isPresent()) { + this.exprName = Optional.of(Utils.normalizeName(this.getClass().getSimpleName(), DEFAULT_EXPRESSION_NAME)); + } + return this.exprName.get(); } /** diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java index 2854704b9223bb..d03669234cddcc 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/NamedExpression.java @@ -21,6 +21,7 @@ import org.apache.doris.nereids.util.Utils; import java.util.List; +import java.util.Optional; /** * Expression in Nereids that having name. @@ -59,6 +60,9 @@ public String getQualifiedName() throws UnboundException { @Override public String getExpressionName() { - return Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME); + if (!this.exprName.isPresent()) { + this.exprName = Optional.of(Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME)); + } + return this.exprName.get(); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java index d6876873ed3de2..451fcad677b829 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/SubqueryExpr.java @@ -86,7 +86,10 @@ public String toSql() { @Override public String getExpressionName() { - return "subquery"; + if (!this.exprName.isPresent()) { + this.exprName = Optional.of("subquery"); + } + return this.exprName.get(); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BoundFunction.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BoundFunction.java index e3970161c7567a..d2089a8d32b470 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BoundFunction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/BoundFunction.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.function.Supplier; import java.util.stream.Collectors; @@ -57,7 +58,10 @@ public String getName() { @Override public String getExpressionName() { - return Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME); + if (!this.exprName.isPresent()) { + this.exprName = Optional.of(Utils.normalizeName(getName(), DEFAULT_EXPRESSION_NAME)); + } + return this.exprName.get(); } public FunctionSignature getSignature() { diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java index c83061f19596fd..fd2b371ea72e67 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/literal/Literal.java @@ -41,6 +41,7 @@ import java.math.BigInteger; import java.util.Locale; import java.util.Objects; +import java.util.Optional; /** * All data type literal expression in Nereids. @@ -133,7 +134,10 @@ public String toSql() { @Override public String getExpressionName() { - return "literal"; + if (!this.exprName.isPresent()) { + this.exprName = Optional.of("literal"); + } + return this.exprName.get(); } @Override From a6d201380225a31ae95621502bfa5256b2bffbf5 Mon Sep 17 00:00:00 2001 From: minghong Date: Wed, 8 Nov 2023 17:15:53 +0800 Subject: [PATCH 49/88] [opt](nereids) use 2 phase agg above union all (#26245) forbid one phase agg for pattern: agg-unionAll one phase agg plan: agg-union-hashDistribute-children two phase agg plan: agg(global) - hashDistribute-agg(local)-union-randomDistribute the key point is the cost of randomDistribute is much lower than the hashDistribute, and hence two-phase agg wins. --- .../doris/nereids/cost/CostModelV1.java | 6 +- .../ChildrenPropertiesRegulator.java | 10 ++ .../plans/physical/PhysicalSetOperation.java | 4 + .../doris/statistics/ColumnStatistic.java | 4 +- .../shape/query1.out | 13 +- .../shape/query49.out | 132 +++++++++--------- .../shape/query75.out | 90 ++++++------ .../shape/query1.out | 13 +- .../shape/query49.out | 132 +++++++++--------- .../shape/query75.out | 90 ++++++------ .../aggregate/agg_union_random.groovy | 54 +++++++ 11 files changed, 314 insertions(+), 234 deletions(-) create mode 100644 regression-test/suites/nereids_p0/aggregate/agg_union_random.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostModelV1.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostModelV1.java index 33b3c80171ac43..72baa7deaf02a5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostModelV1.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/cost/CostModelV1.java @@ -56,6 +56,7 @@ class CostModelV1 extends PlanVisitor { // the penalty factor is no more than BROADCAST_JOIN_SKEW_PENALTY_LIMIT static final double BROADCAST_JOIN_SKEW_RATIO = 30.0; static final double BROADCAST_JOIN_SKEW_PENALTY_LIMIT = 2.0; + static final double RANDOM_SHUFFLE_TO_HASH_SHUFFLE_FACTOR = 0.1; private final int beNumber; public CostModelV1(ConnectContext connectContext) { @@ -217,10 +218,11 @@ public Cost visitPhysicalDistribute( } // any + // cost of randome shuffle is lower than hash shuffle. return CostV1.of(context.getSessionVariable(), - intputRowCount, 0, - 0); + 0, + intputRowCount * childStatistics.dataSizeFactor() * RANDOM_SHUFFLE_TO_HASH_SHUFFLE_FACTOR / beNumber); } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildrenPropertiesRegulator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildrenPropertiesRegulator.java index f0a2331105fa8d..3dfa2615af081c 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildrenPropertiesRegulator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/properties/ChildrenPropertiesRegulator.java @@ -42,6 +42,7 @@ import org.apache.doris.nereids.trees.plans.physical.PhysicalPartitionTopN; import org.apache.doris.nereids.trees.plans.physical.PhysicalProject; import org.apache.doris.nereids.trees.plans.physical.PhysicalSetOperation; +import org.apache.doris.nereids.trees.plans.physical.PhysicalUnion; import org.apache.doris.nereids.trees.plans.visitor.PlanVisitor; import org.apache.doris.nereids.util.JoinUtils; import org.apache.doris.qe.ConnectContext; @@ -117,6 +118,15 @@ public Boolean visitPhysicalHashAggregate(PhysicalHashAggregate && children.get(0).getPlan() instanceof PhysicalDistribute) { return false; } + + // agg(group by x)-union all(A, B) + // no matter x.ndv is high or not, it is not worthwhile to shuffle A and B by x + // and hence we forbid one phase agg + if (agg.getAggMode() == AggMode.INPUT_TO_RESULT + && children.get(0).getPlan() instanceof PhysicalUnion + && !((PhysicalUnion) children.get(0).getPlan()).isDistinct()) { + return false; + } // forbid multi distinct opt that bad than multi-stage version when multi-stage can be executed in one fragment if (agg.getAggMode() == AggMode.INPUT_TO_BUFFER || agg.getAggMode() == AggMode.INPUT_TO_RESULT) { List multiDistinctions = agg.getOutputExpressions().stream() diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSetOperation.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSetOperation.java index 83f15e3f6688d9..ec9537e7cb981a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSetOperation.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/trees/plans/physical/PhysicalSetOperation.java @@ -194,4 +194,8 @@ public List computeOutput() { .map(NamedExpression::toSlot) .collect(ImmutableList.toImmutableList()); } + + public boolean isDistinct() { + return qualifier == Qualifier.DISTINCT; + } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java b/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java index 82e0efdac1784d..1ec22cbc47b013 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java +++ b/fe/fe-core/src/main/java/org/apache/doris/statistics/ColumnStatistic.java @@ -40,7 +40,7 @@ public class ColumnStatistic { public static final double STATS_ERROR = 0.1D; - + public static final double ALMOST_UNIQUE_FACTOR = 0.9; public static final StatsType NDV = StatsType.NDV; public static final StatsType AVG_SIZE = StatsType.AVG_SIZE; public static final StatsType MAX_SIZE = StatsType.MAX_SIZE; @@ -211,7 +211,7 @@ public static ColumnStatistic fromResultRow(ResultRow row) { } public static boolean isAlmostUnique(double ndv, double rowCount) { - return rowCount * 0.9 < ndv && ndv < rowCount * 1.1; + return rowCount * ALMOST_UNIQUE_FACTOR < ndv; } public ColumnStatistic updateByLimit(long limit, double rowCount) { diff --git a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query1.out b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query1.out index 48b94027770508..50d0c4bce6773a 100644 --- a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query1.out +++ b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query1.out @@ -33,10 +33,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ------------------------PhysicalProject --------------------------filter((store.s_state = 'TN')) ----------------------------PhysicalOlapScan[store] -------------------hashAgg[GLOBAL] ---------------------PhysicalDistribute -----------------------hashAgg[LOCAL] -------------------------PhysicalDistribute ---------------------------PhysicalProject -----------------------------PhysicalCteConsumer ( cteId=CTEId#0 ) +------------------PhysicalDistribute +--------------------hashAgg[GLOBAL] +----------------------PhysicalDistribute +------------------------hashAgg[LOCAL] +--------------------------PhysicalDistribute +----------------------------PhysicalProject +------------------------------PhysicalCteConsumer ( cteId=CTEId#0 ) diff --git a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query49.out b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query49.out index 28dfccd68eb301..a8ab13bb0f8d30 100644 --- a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query49.out +++ b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query49.out @@ -4,84 +4,86 @@ PhysicalResultSink --PhysicalTopN ----PhysicalDistribute ------PhysicalTopN ---------hashAgg[LOCAL] -----------PhysicalUnion -------------PhysicalDistribute ---------------PhysicalProject -----------------filter(((return_rank <= 10) OR (currency_rank <= 10))) -------------------PhysicalWindow ---------------------PhysicalQuickSort +--------hashAgg[GLOBAL] +----------PhysicalDistribute +------------hashAgg[LOCAL] +--------------PhysicalUnion +----------------PhysicalDistribute +------------------PhysicalProject +--------------------filter(((return_rank <= 10) OR (currency_rank <= 10))) ----------------------PhysicalWindow ------------------------PhysicalQuickSort ---------------------------PhysicalDistribute +--------------------------PhysicalWindow ----------------------------PhysicalQuickSort -------------------------------PhysicalProject ---------------------------------hashAgg[GLOBAL] -----------------------------------PhysicalDistribute -------------------------------------hashAgg[LOCAL] ---------------------------------------PhysicalProject -----------------------------------------hashJoin[INNER_JOIN] hashCondition=((ws.ws_item_sk = wr.wr_item_sk) and (ws.ws_order_number = wr.wr_order_number))otherCondition=() +------------------------------PhysicalDistribute +--------------------------------PhysicalQuickSort +----------------------------------PhysicalProject +------------------------------------hashAgg[GLOBAL] +--------------------------------------PhysicalDistribute +----------------------------------------hashAgg[LOCAL] ------------------------------------------PhysicalProject ---------------------------------------------filter((wr.wr_return_amt > 10000.00)) -----------------------------------------------PhysicalOlapScan[web_returns] -------------------------------------------hashJoin[INNER_JOIN] hashCondition=((ws.ws_sold_date_sk = date_dim.d_date_sk))otherCondition=() ---------------------------------------------PhysicalProject -----------------------------------------------filter((ws.ws_net_paid > 0.00) and (ws.ws_net_profit > 1.00) and (ws.ws_quantity > 0)) -------------------------------------------------PhysicalOlapScan[web_sales] ---------------------------------------------PhysicalDistribute +--------------------------------------------hashJoin[INNER_JOIN] hashCondition=((ws.ws_item_sk = wr.wr_item_sk) and (ws.ws_order_number = wr.wr_order_number))otherCondition=() ----------------------------------------------PhysicalProject -------------------------------------------------filter((date_dim.d_moy = 11) and (date_dim.d_year = 1998)) ---------------------------------------------------PhysicalOlapScan[date_dim] -------------PhysicalDistribute ---------------PhysicalProject -----------------filter(((return_rank <= 10) OR (currency_rank <= 10))) -------------------PhysicalWindow ---------------------PhysicalQuickSort +------------------------------------------------filter((wr.wr_return_amt > 10000.00)) +--------------------------------------------------PhysicalOlapScan[web_returns] +----------------------------------------------hashJoin[INNER_JOIN] hashCondition=((ws.ws_sold_date_sk = date_dim.d_date_sk))otherCondition=() +------------------------------------------------PhysicalProject +--------------------------------------------------filter((ws.ws_net_paid > 0.00) and (ws.ws_net_profit > 1.00) and (ws.ws_quantity > 0)) +----------------------------------------------------PhysicalOlapScan[web_sales] +------------------------------------------------PhysicalDistribute +--------------------------------------------------PhysicalProject +----------------------------------------------------filter((date_dim.d_moy = 11) and (date_dim.d_year = 1998)) +------------------------------------------------------PhysicalOlapScan[date_dim] +----------------PhysicalDistribute +------------------PhysicalProject +--------------------filter(((return_rank <= 10) OR (currency_rank <= 10))) ----------------------PhysicalWindow ------------------------PhysicalQuickSort ---------------------------PhysicalDistribute +--------------------------PhysicalWindow ----------------------------PhysicalQuickSort -------------------------------PhysicalProject ---------------------------------hashAgg[GLOBAL] -----------------------------------PhysicalDistribute -------------------------------------hashAgg[LOCAL] ---------------------------------------PhysicalProject -----------------------------------------hashJoin[INNER_JOIN] hashCondition=((cs.cs_item_sk = cr.cr_item_sk) and (cs.cs_order_number = cr.cr_order_number))otherCondition=() +------------------------------PhysicalDistribute +--------------------------------PhysicalQuickSort +----------------------------------PhysicalProject +------------------------------------hashAgg[GLOBAL] +--------------------------------------PhysicalDistribute +----------------------------------------hashAgg[LOCAL] ------------------------------------------PhysicalProject ---------------------------------------------filter((cr.cr_return_amount > 10000.00)) -----------------------------------------------PhysicalOlapScan[catalog_returns] -------------------------------------------hashJoin[INNER_JOIN] hashCondition=((cs.cs_sold_date_sk = date_dim.d_date_sk))otherCondition=() ---------------------------------------------PhysicalProject -----------------------------------------------filter((cs.cs_net_paid > 0.00) and (cs.cs_net_profit > 1.00) and (cs.cs_quantity > 0)) -------------------------------------------------PhysicalOlapScan[catalog_sales] ---------------------------------------------PhysicalDistribute +--------------------------------------------hashJoin[INNER_JOIN] hashCondition=((cs.cs_item_sk = cr.cr_item_sk) and (cs.cs_order_number = cr.cr_order_number))otherCondition=() ----------------------------------------------PhysicalProject -------------------------------------------------filter((date_dim.d_moy = 11) and (date_dim.d_year = 1998)) ---------------------------------------------------PhysicalOlapScan[date_dim] -------------PhysicalDistribute ---------------PhysicalProject -----------------filter(((return_rank <= 10) OR (currency_rank <= 10))) -------------------PhysicalWindow ---------------------PhysicalQuickSort +------------------------------------------------filter((cr.cr_return_amount > 10000.00)) +--------------------------------------------------PhysicalOlapScan[catalog_returns] +----------------------------------------------hashJoin[INNER_JOIN] hashCondition=((cs.cs_sold_date_sk = date_dim.d_date_sk))otherCondition=() +------------------------------------------------PhysicalProject +--------------------------------------------------filter((cs.cs_net_paid > 0.00) and (cs.cs_net_profit > 1.00) and (cs.cs_quantity > 0)) +----------------------------------------------------PhysicalOlapScan[catalog_sales] +------------------------------------------------PhysicalDistribute +--------------------------------------------------PhysicalProject +----------------------------------------------------filter((date_dim.d_moy = 11) and (date_dim.d_year = 1998)) +------------------------------------------------------PhysicalOlapScan[date_dim] +----------------PhysicalDistribute +------------------PhysicalProject +--------------------filter(((return_rank <= 10) OR (currency_rank <= 10))) ----------------------PhysicalWindow ------------------------PhysicalQuickSort ---------------------------PhysicalDistribute +--------------------------PhysicalWindow ----------------------------PhysicalQuickSort -------------------------------PhysicalProject ---------------------------------hashAgg[GLOBAL] -----------------------------------PhysicalDistribute -------------------------------------hashAgg[LOCAL] ---------------------------------------PhysicalProject -----------------------------------------hashJoin[INNER_JOIN] hashCondition=((sts.ss_item_sk = sr.sr_item_sk) and (sts.ss_ticket_number = sr.sr_ticket_number))otherCondition=() +------------------------------PhysicalDistribute +--------------------------------PhysicalQuickSort +----------------------------------PhysicalProject +------------------------------------hashAgg[GLOBAL] +--------------------------------------PhysicalDistribute +----------------------------------------hashAgg[LOCAL] ------------------------------------------PhysicalProject ---------------------------------------------filter((sr.sr_return_amt > 10000.00)) -----------------------------------------------PhysicalOlapScan[store_returns] -------------------------------------------hashJoin[INNER_JOIN] hashCondition=((sts.ss_sold_date_sk = date_dim.d_date_sk))otherCondition=() ---------------------------------------------PhysicalProject -----------------------------------------------filter((sts.ss_net_paid > 0.00) and (sts.ss_net_profit > 1.00) and (sts.ss_quantity > 0)) -------------------------------------------------PhysicalOlapScan[store_sales] ---------------------------------------------PhysicalDistribute +--------------------------------------------hashJoin[INNER_JOIN] hashCondition=((sts.ss_item_sk = sr.sr_item_sk) and (sts.ss_ticket_number = sr.sr_ticket_number))otherCondition=() ----------------------------------------------PhysicalProject -------------------------------------------------filter((date_dim.d_moy = 11) and (date_dim.d_year = 1998)) ---------------------------------------------------PhysicalOlapScan[date_dim] +------------------------------------------------filter((sr.sr_return_amt > 10000.00)) +--------------------------------------------------PhysicalOlapScan[store_returns] +----------------------------------------------hashJoin[INNER_JOIN] hashCondition=((sts.ss_sold_date_sk = date_dim.d_date_sk))otherCondition=() +------------------------------------------------PhysicalProject +--------------------------------------------------filter((sts.ss_net_paid > 0.00) and (sts.ss_net_profit > 1.00) and (sts.ss_quantity > 0)) +----------------------------------------------------PhysicalOlapScan[store_sales] +------------------------------------------------PhysicalDistribute +--------------------------------------------------PhysicalProject +----------------------------------------------------filter((date_dim.d_moy = 11) and (date_dim.d_year = 1998)) +------------------------------------------------------PhysicalOlapScan[date_dim] diff --git a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query75.out b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query75.out index 43c13b85a688a6..fb9d10e30ff233 100644 --- a/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query75.out +++ b/regression-test/data/nereids_tpcds_shape_sf1000_p0/shape/query75.out @@ -5,65 +5,67 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ----hashAgg[GLOBAL] ------PhysicalDistribute --------hashAgg[LOCAL] -----------hashAgg[LOCAL] -------------PhysicalUnion ---------------PhysicalDistribute -----------------PhysicalProject -------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((catalog_sales.cs_item_sk = catalog_returns.cr_item_sk) and (catalog_sales.cs_order_number = catalog_returns.cr_order_number))otherCondition=() ---------------------PhysicalProject -----------------------PhysicalOlapScan[catalog_returns] +----------hashAgg[GLOBAL] +------------PhysicalDistribute +--------------hashAgg[LOCAL] +----------------PhysicalUnion +------------------PhysicalDistribute --------------------PhysicalProject -----------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = catalog_sales.cs_sold_date_sk))otherCondition=() +----------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((catalog_sales.cs_item_sk = catalog_returns.cr_item_sk) and (catalog_sales.cs_order_number = catalog_returns.cr_order_number))otherCondition=() +------------------------PhysicalProject +--------------------------PhysicalOlapScan[catalog_returns] ------------------------PhysicalProject ---------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = catalog_sales.cs_item_sk))otherCondition=() +--------------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = catalog_sales.cs_sold_date_sk))otherCondition=() ----------------------------PhysicalProject -------------------------------PhysicalOlapScan[catalog_sales] +------------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = catalog_sales.cs_item_sk))otherCondition=() +--------------------------------PhysicalProject +----------------------------------PhysicalOlapScan[catalog_sales] +--------------------------------PhysicalDistribute +----------------------------------PhysicalProject +------------------------------------filter((item.i_category = 'Sports')) +--------------------------------------PhysicalOlapScan[item] ----------------------------PhysicalDistribute ------------------------------PhysicalProject ---------------------------------filter((item.i_category = 'Sports')) -----------------------------------PhysicalOlapScan[item] -------------------------PhysicalDistribute ---------------------------PhysicalProject -----------------------------filter(d_year IN (2001, 2002)) -------------------------------PhysicalOlapScan[date_dim] ---------------PhysicalDistribute -----------------PhysicalProject -------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((store_sales.ss_item_sk = store_returns.sr_item_sk) and (store_sales.ss_ticket_number = store_returns.sr_ticket_number))otherCondition=() ---------------------PhysicalProject -----------------------PhysicalOlapScan[store_returns] +--------------------------------filter(d_year IN (2001, 2002)) +----------------------------------PhysicalOlapScan[date_dim] +------------------PhysicalDistribute --------------------PhysicalProject -----------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = store_sales.ss_sold_date_sk))otherCondition=() +----------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((store_sales.ss_item_sk = store_returns.sr_item_sk) and (store_sales.ss_ticket_number = store_returns.sr_ticket_number))otherCondition=() ------------------------PhysicalProject ---------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = store_sales.ss_item_sk))otherCondition=() +--------------------------PhysicalOlapScan[store_returns] +------------------------PhysicalProject +--------------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = store_sales.ss_sold_date_sk))otherCondition=() ----------------------------PhysicalProject -------------------------------PhysicalOlapScan[store_sales] +------------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = store_sales.ss_item_sk))otherCondition=() +--------------------------------PhysicalProject +----------------------------------PhysicalOlapScan[store_sales] +--------------------------------PhysicalDistribute +----------------------------------PhysicalProject +------------------------------------filter((item.i_category = 'Sports')) +--------------------------------------PhysicalOlapScan[item] ----------------------------PhysicalDistribute ------------------------------PhysicalProject ---------------------------------filter((item.i_category = 'Sports')) -----------------------------------PhysicalOlapScan[item] -------------------------PhysicalDistribute ---------------------------PhysicalProject -----------------------------filter(d_year IN (2001, 2002)) -------------------------------PhysicalOlapScan[date_dim] ---------------PhysicalDistribute -----------------PhysicalProject -------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((web_sales.ws_item_sk = web_returns.wr_item_sk) and (web_sales.ws_order_number = web_returns.wr_order_number))otherCondition=() +--------------------------------filter(d_year IN (2001, 2002)) +----------------------------------PhysicalOlapScan[date_dim] +------------------PhysicalDistribute --------------------PhysicalProject -----------------------PhysicalOlapScan[web_returns] ---------------------PhysicalProject -----------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = web_sales.ws_sold_date_sk))otherCondition=() +----------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((web_sales.ws_item_sk = web_returns.wr_item_sk) and (web_sales.ws_order_number = web_returns.wr_order_number))otherCondition=() +------------------------PhysicalProject +--------------------------PhysicalOlapScan[web_returns] ------------------------PhysicalProject ---------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = web_sales.ws_item_sk))otherCondition=() +--------------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = web_sales.ws_sold_date_sk))otherCondition=() ----------------------------PhysicalProject -------------------------------PhysicalOlapScan[web_sales] +------------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = web_sales.ws_item_sk))otherCondition=() +--------------------------------PhysicalProject +----------------------------------PhysicalOlapScan[web_sales] +--------------------------------PhysicalDistribute +----------------------------------PhysicalProject +------------------------------------filter((item.i_category = 'Sports')) +--------------------------------------PhysicalOlapScan[item] ----------------------------PhysicalDistribute ------------------------------PhysicalProject ---------------------------------filter((item.i_category = 'Sports')) -----------------------------------PhysicalOlapScan[item] -------------------------PhysicalDistribute ---------------------------PhysicalProject -----------------------------filter(d_year IN (2001, 2002)) -------------------------------PhysicalOlapScan[date_dim] +--------------------------------filter(d_year IN (2001, 2002)) +----------------------------------PhysicalOlapScan[date_dim] --PhysicalResultSink ----PhysicalTopN ------PhysicalDistribute diff --git a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query1.out b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query1.out index 67d53678b41d20..11eb0d9c9b405f 100644 --- a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query1.out +++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query1.out @@ -33,10 +33,11 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ------------------------PhysicalProject --------------------------filter((store.s_state = 'SD')) ----------------------------PhysicalOlapScan[store] -------------------hashAgg[GLOBAL] ---------------------PhysicalDistribute -----------------------hashAgg[LOCAL] -------------------------PhysicalDistribute ---------------------------PhysicalProject -----------------------------PhysicalCteConsumer ( cteId=CTEId#0 ) +------------------PhysicalDistribute +--------------------hashAgg[GLOBAL] +----------------------PhysicalDistribute +------------------------hashAgg[LOCAL] +--------------------------PhysicalDistribute +----------------------------PhysicalProject +------------------------------PhysicalCteConsumer ( cteId=CTEId#0 ) diff --git a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query49.out b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query49.out index 673bc538926663..92cf94f0795728 100644 --- a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query49.out +++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query49.out @@ -4,84 +4,86 @@ PhysicalResultSink --PhysicalTopN ----PhysicalDistribute ------PhysicalTopN ---------hashAgg[LOCAL] -----------PhysicalUnion -------------PhysicalDistribute ---------------PhysicalProject -----------------filter(((return_rank <= 10) OR (currency_rank <= 10))) -------------------PhysicalWindow ---------------------PhysicalQuickSort +--------hashAgg[GLOBAL] +----------PhysicalDistribute +------------hashAgg[LOCAL] +--------------PhysicalUnion +----------------PhysicalDistribute +------------------PhysicalProject +--------------------filter(((return_rank <= 10) OR (currency_rank <= 10))) ----------------------PhysicalWindow ------------------------PhysicalQuickSort ---------------------------PhysicalDistribute +--------------------------PhysicalWindow ----------------------------PhysicalQuickSort -------------------------------PhysicalProject ---------------------------------hashAgg[GLOBAL] -----------------------------------PhysicalDistribute -------------------------------------hashAgg[LOCAL] ---------------------------------------PhysicalProject -----------------------------------------hashJoin[INNER_JOIN] hashCondition=((ws.ws_item_sk = wr.wr_item_sk) and (ws.ws_order_number = wr.wr_order_number))otherCondition=() +------------------------------PhysicalDistribute +--------------------------------PhysicalQuickSort +----------------------------------PhysicalProject +------------------------------------hashAgg[GLOBAL] +--------------------------------------PhysicalDistribute +----------------------------------------hashAgg[LOCAL] ------------------------------------------PhysicalProject ---------------------------------------------filter((wr.wr_return_amt > 10000.00)) -----------------------------------------------PhysicalOlapScan[web_returns] -------------------------------------------hashJoin[INNER_JOIN] hashCondition=((ws.ws_sold_date_sk = date_dim.d_date_sk))otherCondition=() ---------------------------------------------PhysicalProject -----------------------------------------------filter((ws.ws_net_paid > 0.00) and (ws.ws_net_profit > 1.00) and (ws.ws_quantity > 0)) -------------------------------------------------PhysicalOlapScan[web_sales] ---------------------------------------------PhysicalDistribute +--------------------------------------------hashJoin[INNER_JOIN] hashCondition=((ws.ws_item_sk = wr.wr_item_sk) and (ws.ws_order_number = wr.wr_order_number))otherCondition=() ----------------------------------------------PhysicalProject -------------------------------------------------filter((date_dim.d_moy = 12) and (date_dim.d_year = 1999)) ---------------------------------------------------PhysicalOlapScan[date_dim] -------------PhysicalDistribute ---------------PhysicalProject -----------------filter(((return_rank <= 10) OR (currency_rank <= 10))) -------------------PhysicalWindow ---------------------PhysicalQuickSort +------------------------------------------------filter((wr.wr_return_amt > 10000.00)) +--------------------------------------------------PhysicalOlapScan[web_returns] +----------------------------------------------hashJoin[INNER_JOIN] hashCondition=((ws.ws_sold_date_sk = date_dim.d_date_sk))otherCondition=() +------------------------------------------------PhysicalProject +--------------------------------------------------filter((ws.ws_net_paid > 0.00) and (ws.ws_net_profit > 1.00) and (ws.ws_quantity > 0)) +----------------------------------------------------PhysicalOlapScan[web_sales] +------------------------------------------------PhysicalDistribute +--------------------------------------------------PhysicalProject +----------------------------------------------------filter((date_dim.d_moy = 12) and (date_dim.d_year = 1999)) +------------------------------------------------------PhysicalOlapScan[date_dim] +----------------PhysicalDistribute +------------------PhysicalProject +--------------------filter(((return_rank <= 10) OR (currency_rank <= 10))) ----------------------PhysicalWindow ------------------------PhysicalQuickSort ---------------------------PhysicalDistribute +--------------------------PhysicalWindow ----------------------------PhysicalQuickSort -------------------------------PhysicalProject ---------------------------------hashAgg[GLOBAL] -----------------------------------PhysicalDistribute -------------------------------------hashAgg[LOCAL] ---------------------------------------PhysicalProject -----------------------------------------hashJoin[INNER_JOIN] hashCondition=((cs.cs_item_sk = cr.cr_item_sk) and (cs.cs_order_number = cr.cr_order_number))otherCondition=() +------------------------------PhysicalDistribute +--------------------------------PhysicalQuickSort +----------------------------------PhysicalProject +------------------------------------hashAgg[GLOBAL] +--------------------------------------PhysicalDistribute +----------------------------------------hashAgg[LOCAL] ------------------------------------------PhysicalProject ---------------------------------------------filter((cr.cr_return_amount > 10000.00)) -----------------------------------------------PhysicalOlapScan[catalog_returns] -------------------------------------------hashJoin[INNER_JOIN] hashCondition=((cs.cs_sold_date_sk = date_dim.d_date_sk))otherCondition=() ---------------------------------------------PhysicalProject -----------------------------------------------filter((cs.cs_net_paid > 0.00) and (cs.cs_net_profit > 1.00) and (cs.cs_quantity > 0)) -------------------------------------------------PhysicalOlapScan[catalog_sales] ---------------------------------------------PhysicalDistribute +--------------------------------------------hashJoin[INNER_JOIN] hashCondition=((cs.cs_item_sk = cr.cr_item_sk) and (cs.cs_order_number = cr.cr_order_number))otherCondition=() ----------------------------------------------PhysicalProject -------------------------------------------------filter((date_dim.d_moy = 12) and (date_dim.d_year = 1999)) ---------------------------------------------------PhysicalOlapScan[date_dim] -------------PhysicalDistribute ---------------PhysicalProject -----------------filter(((return_rank <= 10) OR (currency_rank <= 10))) -------------------PhysicalWindow ---------------------PhysicalQuickSort +------------------------------------------------filter((cr.cr_return_amount > 10000.00)) +--------------------------------------------------PhysicalOlapScan[catalog_returns] +----------------------------------------------hashJoin[INNER_JOIN] hashCondition=((cs.cs_sold_date_sk = date_dim.d_date_sk))otherCondition=() +------------------------------------------------PhysicalProject +--------------------------------------------------filter((cs.cs_net_paid > 0.00) and (cs.cs_net_profit > 1.00) and (cs.cs_quantity > 0)) +----------------------------------------------------PhysicalOlapScan[catalog_sales] +------------------------------------------------PhysicalDistribute +--------------------------------------------------PhysicalProject +----------------------------------------------------filter((date_dim.d_moy = 12) and (date_dim.d_year = 1999)) +------------------------------------------------------PhysicalOlapScan[date_dim] +----------------PhysicalDistribute +------------------PhysicalProject +--------------------filter(((return_rank <= 10) OR (currency_rank <= 10))) ----------------------PhysicalWindow ------------------------PhysicalQuickSort ---------------------------PhysicalDistribute +--------------------------PhysicalWindow ----------------------------PhysicalQuickSort -------------------------------PhysicalProject ---------------------------------hashAgg[GLOBAL] -----------------------------------PhysicalDistribute -------------------------------------hashAgg[LOCAL] ---------------------------------------PhysicalProject -----------------------------------------hashJoin[INNER_JOIN] hashCondition=((sts.ss_item_sk = sr.sr_item_sk) and (sts.ss_ticket_number = sr.sr_ticket_number))otherCondition=() +------------------------------PhysicalDistribute +--------------------------------PhysicalQuickSort +----------------------------------PhysicalProject +------------------------------------hashAgg[GLOBAL] +--------------------------------------PhysicalDistribute +----------------------------------------hashAgg[LOCAL] ------------------------------------------PhysicalProject ---------------------------------------------filter((sr.sr_return_amt > 10000.00)) -----------------------------------------------PhysicalOlapScan[store_returns] -------------------------------------------hashJoin[INNER_JOIN] hashCondition=((sts.ss_sold_date_sk = date_dim.d_date_sk))otherCondition=() ---------------------------------------------PhysicalProject -----------------------------------------------filter((sts.ss_net_paid > 0.00) and (sts.ss_net_profit > 1.00) and (sts.ss_quantity > 0)) -------------------------------------------------PhysicalOlapScan[store_sales] ---------------------------------------------PhysicalDistribute +--------------------------------------------hashJoin[INNER_JOIN] hashCondition=((sts.ss_item_sk = sr.sr_item_sk) and (sts.ss_ticket_number = sr.sr_ticket_number))otherCondition=() ----------------------------------------------PhysicalProject -------------------------------------------------filter((date_dim.d_moy = 12) and (date_dim.d_year = 1999)) ---------------------------------------------------PhysicalOlapScan[date_dim] +------------------------------------------------filter((sr.sr_return_amt > 10000.00)) +--------------------------------------------------PhysicalOlapScan[store_returns] +----------------------------------------------hashJoin[INNER_JOIN] hashCondition=((sts.ss_sold_date_sk = date_dim.d_date_sk))otherCondition=() +------------------------------------------------PhysicalProject +--------------------------------------------------filter((sts.ss_net_paid > 0.00) and (sts.ss_net_profit > 1.00) and (sts.ss_quantity > 0)) +----------------------------------------------------PhysicalOlapScan[store_sales] +------------------------------------------------PhysicalDistribute +--------------------------------------------------PhysicalProject +----------------------------------------------------filter((date_dim.d_moy = 12) and (date_dim.d_year = 1999)) +------------------------------------------------------PhysicalOlapScan[date_dim] diff --git a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query75.out b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query75.out index 11412b8ea16562..07745a5f3d3a15 100644 --- a/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query75.out +++ b/regression-test/data/nereids_tpcds_shape_sf100_p0/shape/query75.out @@ -5,65 +5,67 @@ PhysicalCteAnchor ( cteId=CTEId#0 ) ----hashAgg[GLOBAL] ------PhysicalDistribute --------hashAgg[LOCAL] -----------hashAgg[LOCAL] -------------PhysicalUnion ---------------PhysicalDistribute -----------------PhysicalProject -------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((catalog_sales.cs_item_sk = catalog_returns.cr_item_sk) and (catalog_sales.cs_order_number = catalog_returns.cr_order_number))otherCondition=() ---------------------PhysicalProject -----------------------PhysicalOlapScan[catalog_returns] +----------hashAgg[GLOBAL] +------------PhysicalDistribute +--------------hashAgg[LOCAL] +----------------PhysicalUnion +------------------PhysicalDistribute --------------------PhysicalProject -----------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = catalog_sales.cs_sold_date_sk))otherCondition=() +----------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((catalog_sales.cs_item_sk = catalog_returns.cr_item_sk) and (catalog_sales.cs_order_number = catalog_returns.cr_order_number))otherCondition=() +------------------------PhysicalProject +--------------------------PhysicalOlapScan[catalog_returns] ------------------------PhysicalProject ---------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = catalog_sales.cs_item_sk))otherCondition=() +--------------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = catalog_sales.cs_sold_date_sk))otherCondition=() ----------------------------PhysicalProject -------------------------------PhysicalOlapScan[catalog_sales] +------------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = catalog_sales.cs_item_sk))otherCondition=() +--------------------------------PhysicalProject +----------------------------------PhysicalOlapScan[catalog_sales] +--------------------------------PhysicalDistribute +----------------------------------PhysicalProject +------------------------------------filter((item.i_category = 'Home')) +--------------------------------------PhysicalOlapScan[item] ----------------------------PhysicalDistribute ------------------------------PhysicalProject ---------------------------------filter((item.i_category = 'Home')) -----------------------------------PhysicalOlapScan[item] -------------------------PhysicalDistribute ---------------------------PhysicalProject -----------------------------filter(d_year IN (1998, 1999)) -------------------------------PhysicalOlapScan[date_dim] ---------------PhysicalDistribute -----------------PhysicalProject -------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((store_sales.ss_item_sk = store_returns.sr_item_sk) and (store_sales.ss_ticket_number = store_returns.sr_ticket_number))otherCondition=() ---------------------PhysicalProject -----------------------PhysicalOlapScan[store_returns] +--------------------------------filter(d_year IN (1998, 1999)) +----------------------------------PhysicalOlapScan[date_dim] +------------------PhysicalDistribute --------------------PhysicalProject -----------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = store_sales.ss_sold_date_sk))otherCondition=() +----------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((store_sales.ss_item_sk = store_returns.sr_item_sk) and (store_sales.ss_ticket_number = store_returns.sr_ticket_number))otherCondition=() ------------------------PhysicalProject ---------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = store_sales.ss_item_sk))otherCondition=() +--------------------------PhysicalOlapScan[store_returns] +------------------------PhysicalProject +--------------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = store_sales.ss_sold_date_sk))otherCondition=() ----------------------------PhysicalProject -------------------------------PhysicalOlapScan[store_sales] +------------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = store_sales.ss_item_sk))otherCondition=() +--------------------------------PhysicalProject +----------------------------------PhysicalOlapScan[store_sales] +--------------------------------PhysicalDistribute +----------------------------------PhysicalProject +------------------------------------filter((item.i_category = 'Home')) +--------------------------------------PhysicalOlapScan[item] ----------------------------PhysicalDistribute ------------------------------PhysicalProject ---------------------------------filter((item.i_category = 'Home')) -----------------------------------PhysicalOlapScan[item] -------------------------PhysicalDistribute ---------------------------PhysicalProject -----------------------------filter(d_year IN (1998, 1999)) -------------------------------PhysicalOlapScan[date_dim] ---------------PhysicalDistribute -----------------PhysicalProject -------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((web_sales.ws_item_sk = web_returns.wr_item_sk) and (web_sales.ws_order_number = web_returns.wr_order_number))otherCondition=() +--------------------------------filter(d_year IN (1998, 1999)) +----------------------------------PhysicalOlapScan[date_dim] +------------------PhysicalDistribute --------------------PhysicalProject -----------------------PhysicalOlapScan[web_returns] ---------------------PhysicalProject -----------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = web_sales.ws_sold_date_sk))otherCondition=() +----------------------hashJoin[RIGHT_OUTER_JOIN] hashCondition=((web_sales.ws_item_sk = web_returns.wr_item_sk) and (web_sales.ws_order_number = web_returns.wr_order_number))otherCondition=() +------------------------PhysicalProject +--------------------------PhysicalOlapScan[web_returns] ------------------------PhysicalProject ---------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = web_sales.ws_item_sk))otherCondition=() +--------------------------hashJoin[INNER_JOIN] hashCondition=((date_dim.d_date_sk = web_sales.ws_sold_date_sk))otherCondition=() ----------------------------PhysicalProject -------------------------------PhysicalOlapScan[web_sales] +------------------------------hashJoin[INNER_JOIN] hashCondition=((item.i_item_sk = web_sales.ws_item_sk))otherCondition=() +--------------------------------PhysicalProject +----------------------------------PhysicalOlapScan[web_sales] +--------------------------------PhysicalDistribute +----------------------------------PhysicalProject +------------------------------------filter((item.i_category = 'Home')) +--------------------------------------PhysicalOlapScan[item] ----------------------------PhysicalDistribute ------------------------------PhysicalProject ---------------------------------filter((item.i_category = 'Home')) -----------------------------------PhysicalOlapScan[item] -------------------------PhysicalDistribute ---------------------------PhysicalProject -----------------------------filter(d_year IN (1998, 1999)) -------------------------------PhysicalOlapScan[date_dim] +--------------------------------filter(d_year IN (1998, 1999)) +----------------------------------PhysicalOlapScan[date_dim] --PhysicalResultSink ----PhysicalTopN ------PhysicalDistribute diff --git a/regression-test/suites/nereids_p0/aggregate/agg_union_random.groovy b/regression-test/suites/nereids_p0/aggregate/agg_union_random.groovy new file mode 100644 index 00000000000000..f233c80dac62ac --- /dev/null +++ b/regression-test/suites/nereids_p0/aggregate/agg_union_random.groovy @@ -0,0 +1,54 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +suite("agg_union_random") { + sql "SET enable_nereids_planner=true" + sql "SET enable_fallback_to_original_planner=false" + sql "DROP TABLE IF EXISTS test_random;" + sql """ + create table test_random + ( + a varchar(100) null, + b decimalv3(18,10) null + ) ENGINE=OLAP + DUPLICATE KEY(`a`) + DISTRIBUTED BY HASH(`a`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + + explain{ + sql "select a from (select * from test_random union all (select * from test_random))t group by a" + /** + STREAM DATA SINK + EXCHANGE ID: 258 + RANDOM + + 252:VOlapScanNode + TABLE: default_cluster:regression_test_nereids_p0_aggregate.test_random(test_random), PREAGGREGATION: ON + partitions=0/1, tablets=0/0, tabletList= + cardinality=1, avgRowSize=0.0, numNodes=1 + pushAggOp=NONE + **/ + contains "RANDOM" + } + + sql "DROP TABLE IF EXISTS test_random;" +} From 45c2fa62a4a5cc80ce9aa812e97185efd8811372 Mon Sep 17 00:00:00 2001 From: HappenLee Date: Wed, 8 Nov 2023 17:51:12 +0800 Subject: [PATCH 50/88] [pipeline](exec) disable shared scan in default and disable shared scan in limit with where scan (#25952) --- .../java/org/apache/doris/common/Config.java | 3 --- .../apache/doris/planner/OlapScanNode.java | 10 +++---- .../org/apache/doris/planner/ScanNode.java | 19 ++++++++++++-- .../java/org/apache/doris/qe/Coordinator.java | 26 +++++++++++++------ .../org/apache/doris/qe/SessionVariable.java | 11 ++++++++ 5 files changed, 50 insertions(+), 19 deletions(-) diff --git a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java index f11ddd1fafc4de..4bdd96aad6557d 100644 --- a/fe/fe-common/src/main/java/org/apache/doris/common/Config.java +++ b/fe/fe-common/src/main/java/org/apache/doris/common/Config.java @@ -1606,9 +1606,6 @@ public class Config extends ConfigBase { @ConfField(mutable = true, varType = VariableAnnotation.EXPERIMENTAL) public static boolean enable_cpu_hard_limit = false; - @ConfField(mutable = true) - public static boolean disable_shared_scan = false; - @ConfField(mutable = false, masterOnly = true) public static int backend_rpc_timeout_ms = 60000; // 1 min diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/OlapScanNode.java b/fe/fe-core/src/main/java/org/apache/doris/planner/OlapScanNode.java index 7167563d8df9dd..45d5910f83deb8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/OlapScanNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/OlapScanNode.java @@ -1267,11 +1267,9 @@ public String getNodeExplainString(String prefix, TExplainLevel detailLevel) { public int getNumInstances() { // In pipeline exec engine, the instance num equals be_num * parallel instance. // so here we need count distinct be_num to do the work. make sure get right instance - if (ConnectContext.get().getSessionVariable().getEnablePipelineEngine()) { - int parallelInstance = ConnectContext.get().getSessionVariable().getParallelExecInstanceNum(); - long numBackend = scanRangeLocations.stream().flatMap(rangeLoc -> rangeLoc.getLocations().stream()) - .map(loc -> loc.backend_id).distinct().count(); - return (int) (parallelInstance * numBackend); + if (ConnectContext.get().getSessionVariable().getEnablePipelineEngine() + && ConnectContext.get().getSessionVariable().getEnableSharedScan()) { + return ConnectContext.get().getSessionVariable().getParallelExecInstanceNum(); } return scanRangeLocations.size(); } @@ -1328,7 +1326,7 @@ public boolean getShouldColoScan() { // If scan is key search, should not enable the shared scan opt to prevent the performance problem // 1. where contain the eq or in expr of key column slot // 2. key column slot is distribution column and first column - public boolean isKeySearch() { + protected boolean isKeySearch() { List whereSlot = Lists.newArrayList(); for (Expr conjunct : conjuncts) { if (conjunct instanceof BinaryPredicate) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/planner/ScanNode.java b/fe/fe-core/src/main/java/org/apache/doris/planner/ScanNode.java index 72f00e68c9e97e..6a409975eaafe5 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/planner/ScanNode.java +++ b/fe/fe-core/src/main/java/org/apache/doris/planner/ScanNode.java @@ -43,6 +43,7 @@ import org.apache.doris.common.UserException; import org.apache.doris.nereids.glue.translator.PlanTranslatorContext; import org.apache.doris.planner.external.FederationBackendPolicy; +import org.apache.doris.qe.ConnectContext; import org.apache.doris.spi.Split; import org.apache.doris.statistics.StatisticalType; import org.apache.doris.statistics.query.StatsDelta; @@ -148,6 +149,13 @@ protected Expr castToSlot(SlotDescriptor slotDesc, Expr expr) throws UserExcepti */ public abstract List getScanRangeLocations(long maxScanRangeLength); + // If scan is key search, should not enable the shared scan opt to prevent the performance problem + // 1. where contain the eq or in expr of key column slot + // 2. key column slot is distribution column and first column + protected boolean isKeySearch() { + return false; + } + /** * Update required_slots in scan node contexts. This is called after Nereids planner do the projection. * In the projection process, some slots may be removed. So call this to update the slots info. @@ -653,7 +661,14 @@ public static TScanRangeLocations createSingleScanRangeLocations(FederationBacke return scanRangeLocation; } - public boolean isKeySearch() { - return false; + // some scan should not enable the shared scan opt to prevent the performance problem + // 1. is key search + // 2. session variable not enable_shared_scan + public boolean shouldDisableSharedScan(ConnectContext context) { + return isKeySearch() || !context.getSessionVariable().getEnableSharedScan(); + } + + public boolean haveLimitAndConjunts() { + return hasLimit() && !conjuncts.isEmpty(); } } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java index 56ca362e69b132..6475230b631561 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/Coordinator.java @@ -1955,20 +1955,24 @@ private void computeFragmentHosts() throws Exception { // disable shared scan optimization if one of conditions below is met: // 1. Use non-pipeline or pipelineX engine - // 2. Number of scan ranges is larger than instances - // 3. This fragment has a colocated scan node - // 4. This fragment has a FileScanNode - // 5. Disable shared scan optimization by session variable - if (!enablePipelineEngine || perNodeScanRanges.size() > parallelExecInstanceNum - || (node.isPresent() && node.get().getShouldColoScan()) + // 2. This fragment has a colocated scan node + // 3. This fragment has a FileScanNode + // 4. Disable shared scan optimization by session variable + if (!enablePipelineEngine || (node.isPresent() && node.get().getShouldColoScan()) || (node.isPresent() && node.get() instanceof FileScanNode) - || (node.isPresent() && node.get().isKeySearch()) - || Config.disable_shared_scan || enablePipelineXEngine) { + || (node.isPresent() && node.get().shouldDisableSharedScan(context)) + || enablePipelineXEngine) { int expectedInstanceNum = 1; if (parallelExecInstanceNum > 1) { //the scan instance num should not larger than the tablets num expectedInstanceNum = Math.min(perNodeScanRanges.size(), parallelExecInstanceNum); } + // if have limit and conjunts, only need 1 instance to save cpu and + // mem resource + if (node.isPresent() && node.get().haveLimitAndConjunts()) { + expectedInstanceNum = 1; + } + perInstanceScanRanges = ListUtil.splitBySize(perNodeScanRanges, expectedInstanceNum); sharedScanOpts = Collections.nCopies(perInstanceScanRanges.size(), false); @@ -1976,6 +1980,12 @@ private void computeFragmentHosts() throws Exception { int expectedInstanceNum = Math.min(parallelExecInstanceNum, leftMostNode.getNumInstances()); expectedInstanceNum = Math.max(expectedInstanceNum, 1); + // if have limit and conjunts, only need 1 instance to save cpu and + // mem resource + if (node.isPresent() && node.get().haveLimitAndConjunts()) { + expectedInstanceNum = 1; + } + perInstanceScanRanges = Collections.nCopies(expectedInstanceNum, perNodeScanRanges); sharedScanOpts = Collections.nCopies(perInstanceScanRanges.size(), true); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java index 955450a15c4452..7a4cef6e40b51e 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/SessionVariable.java @@ -214,6 +214,8 @@ public class SessionVariable implements Serializable, Writable { public static final String ENABLE_PIPELINE_X_ENGINE = "enable_pipeline_x_engine"; + public static final String ENABLE_SHARED_SCAN = "enable_shared_scan"; + public static final String ENABLE_LOCAL_SHUFFLE = "enable_local_shuffle"; public static final String ENABLE_AGG_STATE = "enable_agg_state"; @@ -738,6 +740,11 @@ public class SessionVariable implements Serializable, Writable { @VariableMgr.VarAttr(name = ENABLE_PIPELINE_X_ENGINE, fuzzy = false, varType = VariableAnnotation.EXPERIMENTAL) private boolean enablePipelineXEngine = false; + + @VariableMgr.VarAttr(name = ENABLE_SHARED_SCAN, fuzzy = false, varType = VariableAnnotation.EXPERIMENTAL, + needForward = true) + private boolean enableSharedScan = false; + @VariableMgr.VarAttr(name = ENABLE_LOCAL_SHUFFLE, fuzzy = false, varType = VariableAnnotation.EXPERIMENTAL) private boolean enableLocalShuffle = false; @@ -2832,6 +2839,10 @@ public boolean getEnablePipelineEngine() { return enablePipelineEngine || enablePipelineXEngine; } + public boolean getEnableSharedScan() { + return enableSharedScan; + } + public boolean getEnablePipelineXEngine() { return enablePipelineXEngine; } From 3bce6d38284b2179af96442ce243c7effd4a3894 Mon Sep 17 00:00:00 2001 From: Qi Chen Date: Wed, 8 Nov 2023 18:03:18 +0800 Subject: [PATCH 51/88] [Opt](orc-reader) Optimize orc string dict filter in not_single_conjunct case. (#26386) Optimize orc/parquet string dict filter in not_single_conjunct case. We can optimize this processing to filter block firstly by dict code, then filter by not_single_conjunct. Because dict code is int, it will filter faster than string. For example: ``` select count(l_receiptdate) from lineitem_date_as_string where l_shipmode in ('MAIL', 'SHIP') and l_commitdate < l_receiptdate and l_receiptdate >= '1994-01-01' and l_receiptdate < '1995-01-01'; ``` `l_receiptdate` and `l_shipmode` will using string dict filtering, and `l_commitdate < l_receiptdate` is the an not_single_conjunct which contains dict filter field. We can optimize this processing to filter block firstly by dict code, then filter by not_single_conjunct. Because dict code is int, it will filter faster than string. ### Test Result: Before: mysql> select count(l_receiptdate) from lineitem_date_as_string where l_shipmode in ('MAIL', 'SHIP') and l_commitdate < l_receiptdate and l_receiptdate >= '1994-01-01' and l_receiptdate < '1995-01-01'; +----------------------+ | count(l_receiptdate) | +----------------------+ | 49314694 | +----------------------+ 1 row in set (6.87 sec) After: mysql> select count(l_receiptdate) from lineitem_date_as_string where l_shipmode in ('MAIL', 'SHIP') and l_commitdate < l_receiptdate and l_receiptdate >= '1994-01-01' and l_receiptdate < '1995-01-01'; +----------------------+ | count(l_receiptdate) | +----------------------+ | 49314694 | +----------------------+ 1 row in set (4.85 sec) --- be/src/vec/exec/format/orc/vorc_reader.cpp | 40 ++++++++++--------- be/src/vec/exec/format/orc/vorc_reader.h | 1 + .../format/parquet/vparquet_group_reader.cpp | 12 ++---- 3 files changed, 26 insertions(+), 27 deletions(-) diff --git a/be/src/vec/exec/format/orc/vorc_reader.cpp b/be/src/vec/exec/format/orc/vorc_reader.cpp index 0254c2b85568ea..dd5713abebe354 100644 --- a/be/src/vec/exec/format/orc/vorc_reader.cpp +++ b/be/src/vec/exec/format/orc/vorc_reader.cpp @@ -145,7 +145,8 @@ OrcReader::OrcReader(RuntimeProfile* profile, RuntimeState* state, _ctz(ctz), _is_hive(params.__isset.slot_name_to_schema_pos), _io_ctx(io_ctx), - _enable_lazy_mat(enable_lazy_mat) { + _enable_lazy_mat(enable_lazy_mat), + _is_dict_cols_converted(false) { TimezoneUtils::find_cctz_time_zone(ctz, _time_zone); VecDateTimeValue t; t.from_unixtime(0, ctz); @@ -164,7 +165,8 @@ OrcReader::OrcReader(const TFileScanRangeParams& params, const TFileRangeDesc& r _is_hive(params.__isset.slot_name_to_schema_pos), _file_system(nullptr), _io_ctx(io_ctx), - _enable_lazy_mat(enable_lazy_mat) { + _enable_lazy_mat(enable_lazy_mat), + _is_dict_cols_converted(false) { _init_system_properties(); _init_file_description(); } @@ -1434,7 +1436,6 @@ Status OrcReader::get_next_block(Block* block, size_t* read_rows, bool* eof) { col_name, column_ptr, column_type, _col_orc_type[orc_col_idx->second], batch_vec[orc_col_idx->second], _batch->numElements)); } - *read_rows = rr; RETURN_IF_ERROR(_fill_partition_columns(block, _batch->numElements, _lazy_read_ctx.partition_columns)); @@ -1442,22 +1443,24 @@ Status OrcReader::get_next_block(Block* block, size_t* read_rows, bool* eof) { _fill_missing_columns(block, _batch->numElements, _lazy_read_ctx.missing_columns)); if (block->rows() == 0) { + static_cast(_convert_dict_cols_to_string_cols(block, nullptr)); *eof = true; + *read_rows = 0; return Status::OK(); } + RETURN_IF_CATCH_EXCEPTION(Block::filter_block_internal(block, columns_to_filter, *_filter)); if (!_not_single_slot_filter_conjuncts.empty()) { - std::vector filters; - filters.push_back(_filter.get()); + static_cast(_convert_dict_cols_to_string_cols(block, &batch_vec)); RETURN_IF_CATCH_EXCEPTION( RETURN_IF_ERROR(VExprContext::execute_conjuncts_and_filter_block( - _not_single_slot_filter_conjuncts, &filters, block, columns_to_filter, + _not_single_slot_filter_conjuncts, nullptr, block, columns_to_filter, column_to_keep))); } else { - RETURN_IF_CATCH_EXCEPTION( - Block::filter_block_internal(block, columns_to_filter, *_filter)); Block::erase_useless_column(block, column_to_keep); + static_cast(_convert_dict_cols_to_string_cols(block, &batch_vec)); } + *read_rows = block->rows(); } else { uint64_t rr; SCOPED_RAW_TIMER(&_statistics.column_read_time); @@ -1494,6 +1497,7 @@ Status OrcReader::get_next_block(Block* block, size_t* read_rows, bool* eof) { block->replace_by_position(pos, std::move(dict_col_ptr)); } } + _is_dict_cols_converted = true; std::vector batch_vec; _fill_batch_vec(batch_vec, _batch.get(), 0); @@ -1510,7 +1514,6 @@ Status OrcReader::get_next_block(Block* block, size_t* read_rows, bool* eof) { col_name, column_ptr, column_type, _col_orc_type[orc_col_idx->second], batch_vec[orc_col_idx->second], _batch->numElements)); } - *read_rows = rr; RETURN_IF_ERROR(_fill_partition_columns(block, _batch->numElements, _lazy_read_ctx.partition_columns)); @@ -1520,6 +1523,7 @@ Status OrcReader::get_next_block(Block* block, size_t* read_rows, bool* eof) { if (block->rows() == 0) { static_cast(_convert_dict_cols_to_string_cols(block, nullptr)); *eof = true; + *read_rows = 0; return Status::OK(); } @@ -1557,17 +1561,15 @@ Status OrcReader::get_next_block(Block* block, size_t* read_rows, bool* eof) { static_cast(_convert_dict_cols_to_string_cols(block, &batch_vec)); return Status::OK(); } + RETURN_IF_CATCH_EXCEPTION( + Block::filter_block_internal(block, columns_to_filter, result_filter)); if (!_not_single_slot_filter_conjuncts.empty()) { static_cast(_convert_dict_cols_to_string_cols(block, &batch_vec)); - std::vector merged_filters; - merged_filters.push_back(&result_filter); RETURN_IF_CATCH_EXCEPTION( RETURN_IF_ERROR(VExprContext::execute_conjuncts_and_filter_block( - _not_single_slot_filter_conjuncts, &merged_filters, block, + _not_single_slot_filter_conjuncts, nullptr, block, columns_to_filter, column_to_keep))); } else { - RETURN_IF_CATCH_EXCEPTION( - Block::filter_block_internal(block, columns_to_filter, result_filter)); Block::erase_useless_column(block, column_to_keep); static_cast(_convert_dict_cols_to_string_cols(block, &batch_vec)); } @@ -1579,6 +1581,7 @@ Status OrcReader::get_next_block(Block* block, size_t* read_rows, bool* eof) { Block::erase_useless_column(block, column_to_keep); static_cast(_convert_dict_cols_to_string_cols(block, &batch_vec)); } + *read_rows = block->rows(); } return Status::OK(); } @@ -1640,6 +1643,7 @@ Status OrcReader::filter(orc::ColumnVectorBatch& data, uint16_t* sel, uint16_t s block->replace_by_position(pos, std::move(dict_col_ptr)); } } + _is_dict_cols_converted = true; std::vector batch_vec; _fill_batch_vec(batch_vec, &data, 0); std::vector col_names; @@ -1718,11 +1722,6 @@ Status OrcReader::filter(orc::ColumnVectorBatch& data, uint16_t* sel, uint16_t s new_size += result_filter_data[i] ? 1 : 0; } data.numElements = new_size; - if (data.numElements > 0) { - static_cast(_convert_dict_cols_to_string_cols(block, &batch_vec)); - } else { - static_cast(_convert_dict_cols_to_string_cols(block, nullptr)); - } return Status::OK(); } @@ -2040,6 +2039,9 @@ Status OrcReader::_rewrite_dict_conjuncts(std::vector& dict_codes, int Status OrcReader::_convert_dict_cols_to_string_cols( Block* block, const std::vector* batch_vec) { + if (!_is_dict_cols_converted) { + return Status::OK(); + } for (auto& dict_filter_cols : _dict_filter_cols) { size_t pos = block->get_position_by_name(dict_filter_cols.first); ColumnWithTypeAndName& column_with_type_and_name = block->get_by_position(pos); diff --git a/be/src/vec/exec/format/orc/vorc_reader.h b/be/src/vec/exec/format/orc/vorc_reader.h index 5b50166bcb0a0a..11cdc72bd7ee0f 100644 --- a/be/src/vec/exec/format/orc/vorc_reader.h +++ b/be/src/vec/exec/format/orc/vorc_reader.h @@ -551,6 +551,7 @@ class OrcReader : public GenericReader { std::vector> _dict_filter_cols; std::shared_ptr _obj_pool; std::unique_ptr _string_dict_filter; + bool _is_dict_cols_converted; }; class ORCFileInputStream : public orc::InputStream { diff --git a/be/src/vec/exec/format/parquet/vparquet_group_reader.cpp b/be/src/vec/exec/format/parquet/vparquet_group_reader.cpp index 2c23ed100ec832..abb37a8bfc70c5 100644 --- a/be/src/vec/exec/format/parquet/vparquet_group_reader.cpp +++ b/be/src/vec/exec/format/parquet/vparquet_group_reader.cpp @@ -339,17 +339,15 @@ Status RowGroupReader::next_batch(Block* block, size_t batch_size, size_t* read_ return Status::OK(); } + RETURN_IF_CATCH_EXCEPTION( + Block::filter_block_internal(block, columns_to_filter, result_filter)); if (!_not_single_slot_filter_conjuncts.empty()) { _convert_dict_cols_to_string_cols(block); - std::vector merged_filters; - merged_filters.push_back(&result_filter); RETURN_IF_CATCH_EXCEPTION( RETURN_IF_ERROR(VExprContext::execute_conjuncts_and_filter_block( - _not_single_slot_filter_conjuncts, &merged_filters, block, + _not_single_slot_filter_conjuncts, nullptr, block, columns_to_filter, column_to_keep))); } else { - RETURN_IF_CATCH_EXCEPTION( - Block::filter_block_internal(block, columns_to_filter, result_filter)); Block::erase_useless_column(block, column_to_keep); _convert_dict_cols_to_string_cols(block); } @@ -568,8 +566,6 @@ Status RowGroupReader::_do_lazy_read(Block* block, size_t batch_size, size_t* re RETURN_IF_ERROR(_fill_partition_columns(block, column_size, _lazy_read_ctx.partition_columns)); RETURN_IF_ERROR(_fill_missing_columns(block, column_size, _lazy_read_ctx.missing_columns)); if (!_not_single_slot_filter_conjuncts.empty()) { - std::vector filters; - filters.push_back(&result_filter); RETURN_IF_CATCH_EXCEPTION(RETURN_IF_ERROR(VExprContext::execute_conjuncts_and_filter_block( _not_single_slot_filter_conjuncts, nullptr, block, columns_to_filter, origin_column_num))); @@ -1004,4 +1000,4 @@ ParquetColumnReader::Statistics RowGroupReader::statistics() { return st; } -} // namespace doris::vectorized \ No newline at end of file +} // namespace doris::vectorized From ec874015813b18d5af7da2ff306f7eba6848b788 Mon Sep 17 00:00:00 2001 From: wangbo Date: Wed, 8 Nov 2023 19:23:49 +0800 Subject: [PATCH 52/88] Fix workload group regression test failed (#26579) --- regression-test/data/workload_manager_p0/test_curd_wlg.out | 3 --- .../suites/workload_manager_p0/test_curd_wlg.groovy | 2 -- 2 files changed, 5 deletions(-) diff --git a/regression-test/data/workload_manager_p0/test_curd_wlg.out b/regression-test/data/workload_manager_p0/test_curd_wlg.out index 761d42ab3df680..1a20c3ab216dcd 100644 --- a/regression-test/data/workload_manager_p0/test_curd_wlg.out +++ b/regression-test/data/workload_manager_p0/test_curd_wlg.out @@ -44,6 +44,3 @@ test_group 10 11% false 100 0 0 20% normal 20 50% true 2147483647 0 0 0% test_group 10 11% false 100 0 0 20% --- !select_tvf_2 -- -test_group 0 1 20% - diff --git a/regression-test/suites/workload_manager_p0/test_curd_wlg.groovy b/regression-test/suites/workload_manager_p0/test_curd_wlg.groovy index c65d9603b776c1..7fda3064e11637 100644 --- a/regression-test/suites/workload_manager_p0/test_curd_wlg.groovy +++ b/regression-test/suites/workload_manager_p0/test_curd_wlg.groovy @@ -234,8 +234,6 @@ suite("test_crud_wlg") { // test show workload groups qt_select_tvf_1 "select name,cpu_share,memory_limit,enable_memory_overcommit,max_concurrency,max_queue_size,queue_timeout,cpu_hard_limit from workload_groups() order by name;" - qt_select_tvf_2 "select name, waiting_query_num,running_query_num,cpu_hard_limit from workload_groups() where name='test_group' order by name;" - // test auth sql """drop user if exists test_wlg_user""" sql "CREATE USER 'test_wlg_user'@'%' IDENTIFIED BY '12345';" From 223be6947c4f858a621ce2d85cc51f74d8bcacf4 Mon Sep 17 00:00:00 2001 From: morrySnow <101034200+morrySnow@users.noreply.github.com> Date: Wed, 8 Nov 2023 19:34:32 +0800 Subject: [PATCH 53/88] [opt](Nereids) let DataType toSql same with legacy planner (#26576) --- .../main/java/org/apache/doris/nereids/types/MapType.java | 2 +- .../java/org/apache/doris/nereids/types/StringType.java | 2 +- .../java/org/apache/doris/nereids/types/StructField.java | 5 +++-- .../java/org/apache/doris/nereids/types/StructType.java | 4 ++-- .../java/org/apache/doris/nereids/types/DataTypeTest.java | 2 +- .../suites/query_p0/show/test_nested_complex_switch.groovy | 6 +++--- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/MapType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/MapType.java index d7e11db914f3e5..2f06c1d7f75f9a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/MapType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/MapType.java @@ -104,7 +104,7 @@ public int width() { @Override public String toSql() { - return "MAP<" + keyType.toSql() + ", " + valueType.toSql() + ">"; + return "MAP<" + keyType.toSql() + "," + valueType.toSql() + ">"; } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StringType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StringType.java index 9e130963854fe7..935716e42bf05f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StringType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StringType.java @@ -43,7 +43,7 @@ public Type toCatalogDataType() { @Override public String simpleString() { - return "string"; + return "text"; } @Override diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructField.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructField.java index 73533fc0a58425..e095f25aa66bc8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructField.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructField.java @@ -19,6 +19,7 @@ import org.apache.doris.nereids.util.Utils; +import java.util.Locale; import java.util.Objects; /** @@ -38,7 +39,7 @@ public class StructField { * @param nullable Indicates if values of this field can be `null` values */ public StructField(String name, DataType dataType, boolean nullable, String comment) { - this.name = Objects.requireNonNull(name, "name should not be null"); + this.name = Objects.requireNonNull(name, "name should not be null").toLowerCase(Locale.ROOT); this.dataType = Objects.requireNonNull(dataType, "dataType should not be null"); this.nullable = nullable; this.comment = Objects.requireNonNull(comment, "comment should not be null"); @@ -82,7 +83,7 @@ public org.apache.doris.catalog.StructField toCatalogDataType() { public String toSql() { return name + ":" + dataType.toSql() - + (nullable ? " " : " NOT NULL") + + (nullable ? "" : " NOT NULL") + (comment.isEmpty() ? "" : " COMMENT " + comment); } diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructType.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructType.java index 0e53874b2dc7c3..ef7dd06165ad31 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructType.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/types/StructType.java @@ -119,11 +119,11 @@ public int width() { @Override public String toSql() { - return "STRUCT<" + fields.stream().map(StructField::toSql).collect(Collectors.joining(", ")) + ">"; + return "STRUCT<" + fields.stream().map(StructField::toSql).collect(Collectors.joining(",")) + ">"; } @Override public String toString() { - return "STRUCT<" + fields.stream().map(StructField::toString).collect(Collectors.joining(", ")) + ">"; + return "STRUCT<" + fields.stream().map(StructField::toString).collect(Collectors.joining(",")) + ">"; } } diff --git a/fe/fe-core/src/test/java/org/apache/doris/nereids/types/DataTypeTest.java b/fe/fe-core/src/test/java/org/apache/doris/nereids/types/DataTypeTest.java index c0dfe19d046e33..9f19d815c82d72 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/nereids/types/DataTypeTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/nereids/types/DataTypeTest.java @@ -564,7 +564,7 @@ public void testSimpleName() { Assertions.assertEquals("decimal", DecimalV2Type.SYSTEM_DEFAULT.simpleString()); Assertions.assertEquals("char", new CharType(10).simpleString()); Assertions.assertEquals("varchar", VarcharType.SYSTEM_DEFAULT.simpleString()); - Assertions.assertEquals("string", StringType.INSTANCE.simpleString()); + Assertions.assertEquals("text", StringType.INSTANCE.simpleString()); Assertions.assertEquals("date", DateType.INSTANCE.simpleString()); Assertions.assertEquals("datetime", DateTimeType.INSTANCE.simpleString()); } diff --git a/regression-test/suites/query_p0/show/test_nested_complex_switch.groovy b/regression-test/suites/query_p0/show/test_nested_complex_switch.groovy index 5639d52ddb0d52..af39d8a9c32957 100644 --- a/regression-test/suites/query_p0/show/test_nested_complex_switch.groovy +++ b/regression-test/suites/query_p0/show/test_nested_complex_switch.groovy @@ -170,17 +170,17 @@ suite("test_nested_complex_switch", "query") { // struct test { sql sql_s_s - exception "java.sql.SQLException: errCode = 2, detailMessage = Unsupported field type: STRUCT for STRUCT" + exception "java.sql.SQLException: errCode = 2, detailMessage = Unsupported" } test { sql sql_s_a - exception "java.sql.SQLException: errCode = 2, detailMessage = Unsupported field type: ARRAY for STRUCT" + exception "java.sql.SQLException: errCode = 2, detailMessage = Unsupported" } test { sql sql_s_m - exception "java.sql.SQLException: errCode = 2, detailMessage = Unsupported field type: MAP for STRUCT" + exception "java.sql.SQLException: errCode = 2, detailMessage = Unsupported" } } finally { From d0960bac5613581edc9e2dc00a31a9ceb9b51055 Mon Sep 17 00:00:00 2001 From: bobhan1 Date: Wed, 8 Nov 2023 19:56:31 +0800 Subject: [PATCH 54/88] [Fix](partial update) Fix partial update info loss when the delete bitmaps of the committed transactions are calculated by the compaction (#26556) a fix for #25147 --- be/src/olap/compaction.cpp | 34 +++++++++++++++++----------------- be/src/olap/txn_manager.cpp | 7 +++++-- be/src/olap/txn_manager.h | 7 +++++-- 3 files changed, 27 insertions(+), 21 deletions(-) diff --git a/be/src/olap/compaction.cpp b/be/src/olap/compaction.cpp index b025555166a391..415be6bb0af8a5 100644 --- a/be/src/olap/compaction.cpp +++ b/be/src/olap/compaction.cpp @@ -718,24 +718,24 @@ Status Compaction::modify_rowsets(const Merger::Statistics* stats) { // Therefore, we need to check if every committed rowset has calculated delete bitmap for // all compaction input rowsets. continue; - } else { - DeleteBitmap txn_output_delete_bitmap(_tablet->tablet_id()); - _tablet->calc_compaction_output_rowset_delete_bitmap( - _input_rowsets, _rowid_conversion, 0, UINT64_MAX, &missed_rows, - &location_map, *it.delete_bitmap.get(), &txn_output_delete_bitmap); - if (config::enable_merge_on_write_correctness_check) { - RowsetIdUnorderedSet rowsetids; - rowsetids.insert(_output_rowset->rowset_id()); - _tablet->add_sentinel_mark_to_delete_bitmap(&txn_output_delete_bitmap, - rowsetids); - } - it.delete_bitmap->merge(txn_output_delete_bitmap); - // Step3: write back updated delete bitmap and tablet info. - it.rowset_ids.insert(_output_rowset->rowset_id()); - StorageEngine::instance()->txn_manager()->set_txn_related_delete_bitmap( - it.partition_id, it.transaction_id, _tablet->tablet_id(), - _tablet->tablet_uid(), true, it.delete_bitmap, it.rowset_ids, nullptr); } + DeleteBitmap txn_output_delete_bitmap(_tablet->tablet_id()); + _tablet->calc_compaction_output_rowset_delete_bitmap( + _input_rowsets, _rowid_conversion, 0, UINT64_MAX, &missed_rows, + &location_map, *it.delete_bitmap.get(), &txn_output_delete_bitmap); + if (config::enable_merge_on_write_correctness_check) { + RowsetIdUnorderedSet rowsetids; + rowsetids.insert(_output_rowset->rowset_id()); + _tablet->add_sentinel_mark_to_delete_bitmap(&txn_output_delete_bitmap, + rowsetids); + } + it.delete_bitmap->merge(txn_output_delete_bitmap); + // Step3: write back updated delete bitmap and tablet info. + it.rowset_ids.insert(_output_rowset->rowset_id()); + StorageEngine::instance()->txn_manager()->set_txn_related_delete_bitmap( + it.partition_id, it.transaction_id, _tablet->tablet_id(), + _tablet->tablet_uid(), true, it.delete_bitmap, it.rowset_ids, + it.partial_update_info); } // Convert the delete bitmap of the input rowsets to output rowset for diff --git a/be/src/olap/txn_manager.cpp b/be/src/olap/txn_manager.cpp index af6b0d672359d4..4198d7563260bb 100644 --- a/be/src/olap/txn_manager.cpp +++ b/be/src/olap/txn_manager.cpp @@ -675,11 +675,14 @@ void TxnManager::get_all_commit_tablet_txn_info_by_tablet( const RowsetSharedPtr& rowset = tablet_load_it->second.rowset; const DeleteBitmapPtr& delete_bitmap = tablet_load_it->second.delete_bitmap; const RowsetIdUnorderedSet& rowset_ids = tablet_load_it->second.rowset_ids; + const std::shared_ptr partial_update_info = + tablet_load_it->second.partial_update_info; if (!rowset || !delete_bitmap) { continue; } - commit_tablet_txn_info_vec->push_back(CommitTabletTxnInfo( - partition_id, transaction_id, delete_bitmap, rowset_ids)); + commit_tablet_txn_info_vec->push_back( + CommitTabletTxnInfo(partition_id, transaction_id, delete_bitmap, rowset_ids, + partial_update_info)); } } } diff --git a/be/src/olap/txn_manager.h b/be/src/olap/txn_manager.h index b5a1db0b46ef6e..9fa146710c0a01 100644 --- a/be/src/olap/txn_manager.h +++ b/be/src/olap/txn_manager.h @@ -101,15 +101,18 @@ struct TabletTxnInfo { struct CommitTabletTxnInfo { CommitTabletTxnInfo(TPartitionId partition_id, TTransactionId transaction_id, - DeleteBitmapPtr delete_bitmap, RowsetIdUnorderedSet rowset_ids) + DeleteBitmapPtr delete_bitmap, RowsetIdUnorderedSet rowset_ids, + std::shared_ptr partial_update_info) : transaction_id(transaction_id), partition_id(partition_id), delete_bitmap(delete_bitmap), - rowset_ids(rowset_ids) {} + rowset_ids(rowset_ids), + partial_update_info(partial_update_info) {} TTransactionId transaction_id; TPartitionId partition_id; DeleteBitmapPtr delete_bitmap; RowsetIdUnorderedSet rowset_ids; + std::shared_ptr partial_update_info; }; using CommitTabletTxnInfoVec = std::vector; From d749d99fe294182cc1d1ee826e61fc25bf3a4d50 Mon Sep 17 00:00:00 2001 From: starocean999 <40539150+starocean999@users.noreply.github.com> Date: Wed, 8 Nov 2023 20:45:58 +0800 Subject: [PATCH 55/88] [fix](nereids)don't normalize column name for base index (#26476) --- .../SelectMaterializedIndexWithAggregate.java | 17 +++++++++++------ .../with/test_with_and_two_phase_agg.groovy | 10 +++++----- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMaterializedIndexWithAggregate.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMaterializedIndexWithAggregate.java index abc842cb9a86ed..1b6b26077fe857 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMaterializedIndexWithAggregate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/mv/SelectMaterializedIndexWithAggregate.java @@ -30,7 +30,6 @@ import org.apache.doris.nereids.rules.Rule; import org.apache.doris.nereids.rules.RuleType; import org.apache.doris.nereids.rules.rewrite.RewriteRuleFactory; -import org.apache.doris.nereids.rules.rewrite.mv.AbstractSelectMaterializedIndexRule.SlotContext; import org.apache.doris.nereids.trees.expressions.Alias; import org.apache.doris.nereids.trees.expressions.Cast; import org.apache.doris.nereids.trees.expressions.ExprId; @@ -940,6 +939,7 @@ private static class CheckContext { public CheckContext(LogicalOlapScan scan, long indexId) { this.scan = scan; + boolean isBaseIndex = indexId == scan.getTable().getBaseIndexId(); Supplier> supplier = () -> Maps.newTreeMap(String.CASE_INSENSITIVE_ORDER); @@ -947,15 +947,20 @@ public CheckContext(LogicalOlapScan scan, long indexId) { Map> baseNameToColumnGroupingByIsKey = scan.getTable() .getSchemaByIndexId(indexId).stream() .collect(Collectors.groupingBy(Column::isKey, - Collectors.toMap(c -> normalizeName(parseMvColumnToSql(c.getName())), Function.identity(), - (v1, v2) -> v1, supplier))); + Collectors.toMap( + c -> isBaseIndex ? c.getName() + : normalizeName(parseMvColumnToSql(c.getName())), + Function.identity(), (v1, v2) -> v1, supplier))); Map> mvNameToColumnGroupingByIsKey = scan.getTable() .getSchemaByIndexId(indexId).stream() .collect(Collectors.groupingBy(Column::isKey, Collectors.toMap( - c -> normalizeName(parseMvColumnToMvName(c.getNameWithoutMvPrefix(), - c.isAggregated() ? Optional.of(c.getAggregationType().name()) - : Optional.empty())), + c -> isBaseIndex ? c.getName() + : normalizeName(parseMvColumnToMvName( + c.getNameWithoutMvPrefix(), + c.isAggregated() + ? Optional.of(c.getAggregationType().name()) + : Optional.empty())), Function.identity(), (v1, v2) -> v1, supplier))); this.keyNameToColumn = mvNameToColumnGroupingByIsKey.getOrDefault(true, diff --git a/regression-test/suites/nereids_p0/with/test_with_and_two_phase_agg.groovy b/regression-test/suites/nereids_p0/with/test_with_and_two_phase_agg.groovy index 6b80546bc70185..c7b5865219a0aa 100644 --- a/regression-test/suites/nereids_p0/with/test_with_and_two_phase_agg.groovy +++ b/regression-test/suites/nereids_p0/with/test_with_and_two_phase_agg.groovy @@ -22,21 +22,21 @@ suite("test_with_and_two_phase_agg") { sql """ DROP TABLE IF EXISTS ${tableName} """ sql """ CREATE TABLE IF NOT EXISTS ${tableName}( - `key1` int not null, + `key` int not null, `key2` varchar(50) not null, `account` varchar(50) not null ) ENGINE = OLAP - UNIQUE KEY (`key1`, `key2`) - DISTRIBUTED BY HASH(`key1`) + UNIQUE KEY (`key`, `key2`) + DISTRIBUTED BY HASH(`key`) PROPERTIES("replication_num" = "1"); """ sql """ INSERT INTO ${tableName} VALUES (1, '1332050726', '1332050726'); """ qt_select """ - WITH t2 AS( SELECT sum(`key1`) num, COUNT(DISTINCT `account`) unt + WITH t2 AS( SELECT sum(`key`) num, COUNT(DISTINCT `account`) unt FROM ${tableName}) SELECT num FROM t2; """ qt_select2 """ - WITH t2 AS( SELECT `key2`, sum(`key1`) num, COUNT(DISTINCT `account`) unt + WITH t2 AS( SELECT `key2`, sum(`key`) num, COUNT(DISTINCT `account`) unt FROM ${tableName} GROUP BY `key2`) SELECT num FROM t2; """ } From 0c1458f21f6142a707b59f3923aba4f0b578bf93 Mon Sep 17 00:00:00 2001 From: starocean999 <40539150+starocean999@users.noreply.github.com> Date: Wed, 8 Nov 2023 20:46:29 +0800 Subject: [PATCH 56/88] [fix](planner)isnull predicate can't be safely constant folded in inlineview (#25377) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit disable is null predicate constant fold rule for inline view consider sql select c.* from ( select a.*, b.x from test_insert a left join (select 'some_const_str' x from test_insert) b on true ) c where c.x is null; when push “c.x is null” into c, after folding constant rule, it will get empty result. Because x is 'some_const_str' and "x is null" will be evaluated to false. This is wrong. --- .../java/org/apache/doris/analysis/IsNullPredicate.java | 2 +- .../java/org/apache/doris/rewrite/FoldConstantsRule.java | 6 +++++- .../suites/query_p0/literal_view/lietral_test.groovy | 6 ++++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/IsNullPredicate.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/IsNullPredicate.java index bf81cb48100d02..c67ca1b06029db 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/IsNullPredicate.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/IsNullPredicate.java @@ -160,7 +160,7 @@ public Expr getResultValue(boolean forPushDownPredicatesToView) throws AnalysisE // after outer join recursiveResetChildrenResult(!forPushDownPredicatesToView); final Expr childValue = getChild(0); - if (!(childValue instanceof LiteralExpr)) { + if (forPushDownPredicatesToView || !(childValue instanceof LiteralExpr)) { return this; } return childValue instanceof NullLiteral ? new BoolLiteral(!isNotNull) : new BoolLiteral(isNotNull); diff --git a/fe/fe-core/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java b/fe/fe-core/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java index 509e78ffb8b641..e28feabbf4d430 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java +++ b/fe/fe-core/src/main/java/org/apache/doris/rewrite/FoldConstantsRule.java @@ -29,6 +29,7 @@ import org.apache.doris.analysis.InformationFunction; import org.apache.doris.analysis.LiteralExpr; import org.apache.doris.analysis.NullLiteral; +import org.apache.doris.analysis.SlotRef; import org.apache.doris.analysis.VariableExpr; import org.apache.doris.catalog.Env; import org.apache.doris.catalog.PrimitiveType; @@ -124,7 +125,10 @@ public Expr apply(Expr expr, Analyzer analyzer, ExprRewriter.ClauseType clauseTy return expr; } } - return expr.getResultValue(false); + // it may be wrong to fold constant value in inline view + // so pass the info to getResultValue method to let predicate itself + // to decide if it can fold constant value safely + return expr.getResultValue(expr instanceof SlotRef ? false : analyzer.isInlineViewAnalyzer()); } /** diff --git a/regression-test/suites/query_p0/literal_view/lietral_test.groovy b/regression-test/suites/query_p0/literal_view/lietral_test.groovy index 905ed6696dd31f..b19f33e2939685 100644 --- a/regression-test/suites/query_p0/literal_view/lietral_test.groovy +++ b/regression-test/suites/query_p0/literal_view/lietral_test.groovy @@ -140,4 +140,10 @@ suite("literal_view_test") { sql "select * from (select null as top) t where top = 5" result ([]) } + + sql """set enable_nereids_planner=false;""" + explain { + sql """ select c.* from ( select a.*, '' x from test_insert a left join test_insert b on true ) c where c.x is null; """ + notContains("VEMPTYSET") + } } From e718952e89bb80ab85d38ea33df782ab48e6369e Mon Sep 17 00:00:00 2001 From: starocean999 <40539150+starocean999@users.noreply.github.com> Date: Wed, 8 Nov 2023 20:46:40 +0800 Subject: [PATCH 57/88] [fix](nereids)only enable colocate scan for one phase global parttion topn in some condition (#26473) --- .../nereids/glue/translator/PhysicalPlanTranslator.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java index d4c6fe07c323d3..53ffb36e1e57ed 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/glue/translator/PhysicalPlanTranslator.java @@ -85,6 +85,7 @@ import org.apache.doris.nereids.trees.plans.AggMode; import org.apache.doris.nereids.trees.plans.AggPhase; import org.apache.doris.nereids.trees.plans.JoinType; +import org.apache.doris.nereids.trees.plans.PartitionTopnPhase; import org.apache.doris.nereids.trees.plans.Plan; import org.apache.doris.nereids.trees.plans.PreAggStatus; import org.apache.doris.nereids.trees.plans.physical.AbstractPhysicalJoin; @@ -1546,8 +1547,8 @@ public PlanFragment visitPhysicalPartitionTopN(PhysicalPartitionTopN Date: Wed, 8 Nov 2023 20:54:35 +0800 Subject: [PATCH 58/88] [opt](nereids)replace scan by empty relation when all partitions are pruned (#26514) * replace scan by empty relation when all partitions are pruned --- .../rules/rewrite/PruneOlapScanPartition.java | 7 ++++ .../data/empty_relation/eliminate_empty.out | 10 ++++++ .../empty_relation/eliminate_empty.groovy | 36 +++++++++++++++++++ 3 files changed, 53 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PruneOlapScanPartition.java b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PruneOlapScanPartition.java index 1bdff7f6c10eba..db183d663897c0 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PruneOlapScanPartition.java +++ b/fe/fe-core/src/main/java/org/apache/doris/nereids/rules/rewrite/PruneOlapScanPartition.java @@ -24,9 +24,11 @@ import org.apache.doris.nereids.rules.expression.rules.PartitionPruner; import org.apache.doris.nereids.rules.expression.rules.PartitionPruner.PartitionTableType; import org.apache.doris.nereids.trees.expressions.Slot; +import org.apache.doris.nereids.trees.plans.logical.LogicalEmptyRelation; import org.apache.doris.nereids.trees.plans.logical.LogicalFilter; import org.apache.doris.nereids.trees.plans.logical.LogicalOlapScan; import org.apache.doris.nereids.util.Utils; +import org.apache.doris.qe.ConnectContext; import com.google.common.collect.ImmutableList; import org.apache.commons.collections.CollectionUtils; @@ -73,6 +75,11 @@ public Rule build() { if (!CollectionUtils.isEmpty(manuallySpecifiedPartitions)) { prunedPartitions.retainAll(manuallySpecifiedPartitions); } + if (prunedPartitions.isEmpty()) { + return new LogicalEmptyRelation( + ConnectContext.get().getStatementContext().getNextRelationId(), + filter.getOutput()); + } LogicalOlapScan rewrittenScan = scan.withSelectedPartitionIds(ImmutableList.copyOf(prunedPartitions)); return new LogicalFilter<>(filter.getConjuncts(), rewrittenScan); }).toRule(RuleType.OLAP_SCAN_PARTITION_PRUNE); diff --git a/regression-test/data/empty_relation/eliminate_empty.out b/regression-test/data/empty_relation/eliminate_empty.out index e864cd46e3fa91..0bcc266b1c2888 100644 --- a/regression-test/data/empty_relation/eliminate_empty.out +++ b/regression-test/data/empty_relation/eliminate_empty.out @@ -70,3 +70,13 @@ PhysicalResultSink -- !except_empty_data -- +-- !prune_partition1 -- +PhysicalResultSink +--PhysicalProject +----PhysicalEmptyRelation + +-- !prune_partition2 -- +PhysicalResultSink +--PhysicalProject +----PhysicalEmptyRelation + diff --git a/regression-test/suites/empty_relation/eliminate_empty.groovy b/regression-test/suites/empty_relation/eliminate_empty.groovy index d9050e9cdc1b18..326fa69d376c55 100644 --- a/regression-test/suites/empty_relation/eliminate_empty.groovy +++ b/regression-test/suites/empty_relation/eliminate_empty.groovy @@ -127,4 +127,40 @@ suite("eliminate_empty") { qt_except_empty_data """ select r_regionkey from region where false except select n_nationkey from nation """ + + sql """ + drop table if exists eliminate_partition_prune; + """ + sql """ + CREATE TABLE `eliminate_partition_prune` ( + `k1` int(11) NULL COMMENT "", + `k2` int(11) NULL COMMENT "", + `k3` int(11) NULL COMMENT "" + ) + PARTITION BY RANGE(`k1`, `k2`) + (PARTITION p1 VALUES LESS THAN ("3", "1"), + PARTITION p2 VALUES [("3", "1"), ("7", "10")), + PARTITION p3 VALUES [("7", "10"), ("10", "15"))) + DISTRIBUTED BY HASH(`k1`) BUCKETS 10 + PROPERTIES ('replication_num' = '1'); + """ + + + qt_prune_partition1 """ + explain shape plan + select sum(k2) + from + (select * from eliminate_partition_prune where k1=100) T + group by k3; + """ + sql """ + insert into eliminate_partition_prune values (7, 0, 0) + """ + qt_prune_partition2 """ + explain shape plan + select sum(k2) + from + (select * from eliminate_partition_prune where k1=100) T + group by k3; + """ } \ No newline at end of file From 1fc360df1931099653403974f3c640889efeb7f2 Mon Sep 17 00:00:00 2001 From: Dongyang Li Date: Wed, 8 Nov 2023 21:25:55 +0800 Subject: [PATCH 59/88] [ci](p0) support run p0 10 times (#26603) * [ci](p0) support run mutiple time Co-authored-by: stephen --- .github/workflows/auto_trigger_teamcity.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/auto_trigger_teamcity.yml b/.github/workflows/auto_trigger_teamcity.yml index 61be077fed6857..6e2a1bf97e4422 100644 --- a/.github/workflows/auto_trigger_teamcity.yml +++ b/.github/workflows/auto_trigger_teamcity.yml @@ -62,6 +62,7 @@ jobs: fi if [[ "${comment_message}" =~ "run" && "${comment_message}" =~ " p0" && ! "${comment_message}" =~ "Thanks for your contribution" ]]; then trigger_pipelines="Doris_DorisRegression_P0Regression ${trigger_pipelines}" + if [[ "${comment_message}" = *"10" ]]; then repeat_times="10"; fi fi if [[ "${comment_message}" =~ "run" && "${comment_message}" =~ " pipelinex_p0" && ! "${comment_message}" =~ "Thanks for your contribution" ]]; then trigger_pipelines="Doris_DorisRegression_P0RegressionPipelineX ${trigger_pipelines}" @@ -133,7 +134,12 @@ jobs: if [ "_""${same_build_sign}" == "_false" ];then sleep 10s echo "there is no running build or queue build, so trigger a new !" - execute_command="curl -s -X POST ${teamcity_url}/httpAuth/action.html\?add2Queue\=${pipeline}\&branchName\=pull/${pull_request_num}\&name=env.latest_pr_comment\&value=${encoded_string}\&name=env.latest_commit_id\&value=${latest_commit_id}" + echo "repeat_times: ${repeat_times}" + if [[ -n "${repeat_times}" ]]; then + execute_command="curl -s -X POST ${teamcity_url}/httpAuth/action.html\?add2Queue\=${pipeline}\&branchName\=pull/${pull_request_num}\&name=env.latest_pr_comment\&value=${encoded_string}\&name=env.latest_commit_id\&value=${latest_commit_id}\&name=env.repeat_times\&value=${repeat_times}" + else + execute_command="curl -s -X POST ${teamcity_url}/httpAuth/action.html\?add2Queue\=${pipeline}\&branchName\=pull/${pull_request_num}\&name=env.latest_pr_comment\&value=${encoded_string}\&name=env.latest_commit_id\&value=${latest_commit_id}" + fi echo "${execute_command}" eval "${execute_command}" echo "-----------------------------------------------------------------" From 5bcf6bfd468f699af1b817a1a6301675b59638de Mon Sep 17 00:00:00 2001 From: zy-kkk Date: Wed, 8 Nov 2023 21:41:56 +0800 Subject: [PATCH 60/88] [fix](jdbc catalog) fix mysql zero date (#26569) --- .../mysql/init/03-create-table.sql | 5 + .../docker-compose/mysql/init/04-insert.sql | 5 + docs/en/docs/lakehouse/multi-catalog/jdbc.md | 132 ++++++++---------- .../docs/lakehouse/multi-catalog/jdbc.md | 52 +++---- .../jdbc/client/JdbcMySQLClient.java | 3 + .../jdbc/test_mysql_jdbc_catalog.out | 4 + .../jdbc/test_mysql_jdbc_catalog.groovy | 2 + 7 files changed, 96 insertions(+), 107 deletions(-) diff --git a/docker/thirdparties/docker-compose/mysql/init/03-create-table.sql b/docker/thirdparties/docker-compose/mysql/init/03-create-table.sql index 4663ea2cf6ee45..ee44e1c87a2bf5 100644 --- a/docker/thirdparties/docker-compose/mysql/init/03-create-table.sql +++ b/docker/thirdparties/docker-compose/mysql/init/03-create-table.sql @@ -321,3 +321,8 @@ CREATE TABLE show_test_do_not_modify.ex_tb2 ( id int, count_value varchar(20) ); + +CREATE TABLE doris_test.test_zd ( +`id` int(10) unsigned NOT NULL, +`d_z` date NOT NULL +); diff --git a/docker/thirdparties/docker-compose/mysql/init/04-insert.sql b/docker/thirdparties/docker-compose/mysql/init/04-insert.sql index 93ae8c9b63e5ff..3ff51a9a123837 100644 --- a/docker/thirdparties/docker-compose/mysql/init/04-insert.sql +++ b/docker/thirdparties/docker-compose/mysql/init/04-insert.sql @@ -1152,3 +1152,8 @@ VALUES ('2023-06-17 10:00:00', '2023-06-17 10:00:01.1', '2023-06-17 10:00:02.22' SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'STRICT_TRANS_TABLES','')); INSERT INTO doris_test.dt_null VALUES ('2023-06-17 10:00:00'),('0000-00-00 00:00:00'); + +SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'NO_ZERO_DATE','')); +SET SESSION sql_mode=(SELECT REPLACE(@@sql_mode,'NO_ZERO_IN_DATE','')); + +insert into doris_test.test_zd (id,d_z) VALUES (1,'0000-00-00'),(2,'2022-01-01'); diff --git a/docs/en/docs/lakehouse/multi-catalog/jdbc.md b/docs/en/docs/lakehouse/multi-catalog/jdbc.md index d62948460622b0..db41b033a49aac 100644 --- a/docs/en/docs/lakehouse/multi-catalog/jdbc.md +++ b/docs/en/docs/lakehouse/multi-catalog/jdbc.md @@ -695,60 +695,59 @@ DROP CATALOG ; SET NAMES utf8mb4 ``` -3. Why does the error message "CAUSED BY: DataReadException: Zero date value prohibited" pop up when DateTime="0000:00:00 00:00:00" while reading MySQL external tables? +3. Exception occurs when reading MySQL date/datetime type - This error occurs because of an illegal DateTime. It can be fixed by modifying the `zeroDateTimeBehavior` parameter. - - The options for this parameter include: `EXCEPTION`,`CONVERT_TO_NULL`,`ROUND`. Respectively, they mean to report error, convert to null, and round the DateTime to "0001-01-01 00:00:00" when encountering an illegal DateTime. - - You can add `"jdbc_url"="jdbc:mysql://IP:PORT/doris_test?zeroDateTimeBehavior=convertToNull"` to the URL. - -4. Why do loading failures happen when reading MySQL or other external tables? + ``` + ERROR 1105 (HY000): errCode = 2, detailMessage = (10.16.10.6)[INTERNAL_ERROR]UdfRuntimeException: get next block failed: + CAUSED BY: SQLException: Zero date value prohibited + CAUSED BY: DataReadException: Zero date value prohibited + ``` - For example: + This is because the default handling of illegal Date/DateTime in JDBC is to throw an exception, and this behavior can be controlled through the parameter `zeroDateTimeBehavior`. - ``` - failed to load driver class com.mysql.jdbc.driver in either of hikariconfig class loader - ``` + The optional parameters are: `EXCEPTION`, `CONVERT_TO_NULL`, `ROUND`, respectively: exception error reporting, converted to NULL value, converted to "0001-01-01 00:00:00"; - Such errors occur because the `driver_class` has been wrongly put when creating the catalog. The problem with the above example is the letter case. It should be corrected as `"driver_class" = "com.mysql.jdbc.Driver"`. + You need to add `zeroDateTimeBehavior=convertToNull` to the end of the JDBC connection string when creating the Catalog `jdbc_url`, such as `"jdbc_url" = "jdbc:mysql://127.0.0.1:3306/test?zeroDateTimeBehavior=convertToNull"` + In this case, JDBC will convert 0000-00-00 or 0000-00-00 00:00:00 into null, and then Doris will process all Date/DateTime type columns in the current Catalog as nullable types, so that It can be read normally. -5. There is a communication link exception in reading MySQL +4. When reading the MySQL table or other tables, a class loading failure occurs. - If you run into the following errors: + Such as the following exception: - ``` - ERROR 1105 (HY000): errCode = 2, detailMessage = PoolInitializationException: Failed to initialize pool: Communications link failure - - The last packet successfully received from the server was 7 milliseconds ago. The last packet sent successfully to the server was 4 milliseconds ago. - CAUSED BY: CommunicationsException: Communications link failure - - The last packet successfully received from the server was 7 milliseconds ago. The last packet sent successfully to the server was 4 milliseconds ago. - CAUSED BY: SSLHandshakeExcepti - ``` + ``` + failed to load driver class com.mysql.jdbc.driver in either of hikariconfig class loader + ``` - Please check the be.out log of BE. + This is because when creating the catalog, the driver_class filled in is incorrect and needs to be filled in correctly. For example, the above example has a case problem and should be filled in as `"driver_class" = "com.mysql.jdbc.Driver"` - If it contains the following message: +5. Communication link abnormality occurs when reading MySQL - ``` - WARN: Establishing SSL connection without server's identity verification is not recommended. - According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. - For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. - You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification. - ``` + If the following error occurs: - You can add `?useSSL=false` to the end of the JDBC connection string when creating Catalog. For example, `"jdbc_url" = "jdbc:mysql://127.0.0.1:3306/test?useSSL=false"`. + ``` + ERROR 1105 (HY000): errCode = 2, detailMessage = PoolInitializationException: Failed to initialize pool: Communications link failure + + The last packet successfully received from the server was 7 milliseconds ago. The last packet sent successfully to the server was 4 milliseconds ago. + CAUSED BY: CommunicationsException: Communications link failure + + The last packet successfully received from the server was 7 milliseconds ago. The last packet sent successfully to the server was 4 milliseconds ago. + CAUSED BY: SSLHandshakeExcepti + ``` -6. What to do with the `OutOfMemoryError` when querying MySQL databases? + You can view be’s be.out log - To reduce memory usage, Doris obtains one batch of query results at a time, and has a size limit for each batch. However, MySQL conducts one-off loading of all query results by default, which means the "loading in batches" method won't work. To solve this, you need to specify "jdbc_url"="jdbc:mysql://IP:PORT/doris_test?useCursorFetch=true" in the URL. + If the following information is included: -7. What to do with errors such as "CAUSED BY: SQLException OutOfMemoryError" when performing JDBC queries? + ``` + WARN: Establishing SSL connection without server's identity verification is not recommended. + According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. + For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. + You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification. + ``` - If you have set `useCursorFetch` for MySQL, you can increase the JVM memory limit by modifying the value of `jvm_max_heap_size` in be.conf. The current default value is 1024M. + You can add `?useSSL=false` to the end of the JDBC connection string when creating the Catalog, such as `"jdbc_url" = "jdbc:mysql://127.0.0.1:3306/test?useSSL=false"` -8. When using JDBC to query MySQL large data volume, if the query can occasionally succeed, occasionally report the following errors, and all the MySQL connections are completely disconnected when the error occurs: +6. When using JDBC to query large amounts of MYSQL data, if the query is occasionally successful, the following error will occasionally be reported. When this error occurs, all MYSQL connections are disconnected and cannot be connected to MYSQL SERVER. After a while, mysql returns to normal. , but the previous connections are gone: ``` ERROR 1105 (HY000): errCode = 2, detailMessage = [INTERNAL_ERROR]UdfRuntimeException: JDBC executor sql has error: @@ -756,35 +755,28 @@ DROP CATALOG ; The last packet successfully received from the server was 4,446 milliseconds ago. The last packet sent successfully to the server was 4,446 milliseconds ago. ``` - When the above phenomenon appears, it may be that mysql server's own memory or CPU resources are exhausted and the MySQL service is unavailable. You can try to increase the memory or CPU resources of MySQL Server. + When the above phenomenon occurs, it may be that Mysql Server's own memory or CPU resources are exhausted, causing the Mysql service to be unavailable. You can try to increase the memory or CPU configuration of Mysql Server. -9. If the results are inconsistent with those in the MYSQL database when you query the MYSQL database using JDBC +7. During the process of using JDBC to query MYSQL, if it is found that the query results are inconsistent with the query results in the MYSQL library - First check whether the string in the query field is case-sensitive. For example, there is a field c_1 in the Table with two - - data "aaa" and "AAA". If the MYSQL database is not case-sensitive when initializing the MYSQL database, mysql is - - case-insensitive by default, but Doris is strictly case-sensitive, so the following situations will occur: + First, check whether the string in the query field is case-sensitive. For example, there is a field c_1 in Table that contains two pieces of data: "aaa" and "AAA". If no distinguishing string is specified when initializing the MYSQL database, + Case, then MYSQL is not case-sensitive in strings by default, but in Doris it is strictly case-sensitive, so the following situations will occur: ``` - Mysql behavior: - select count(c_1) from table where c_1 = "aaa"; The string size is not distinguished, so the result is : 2 + Mysql behavior: + select count(c_1) from table where c_1 = "aaa"; The string size is not distinguished, so the result is: 2 - Doris behavior: - select count(c_1) from table where c_1 = "aaa"; Strictly delimit the string size, so the result is : 1 + Doris behavior: + select count(c_1) from table where c_1 = "aaa"; strictly distinguishes the string size, so the result is: 1 ``` - If the above phenomenon occurs, it needs to be adjusted according to demand, as follows: + If the above phenomenon occurs, it needs to be adjusted according to needs, as follows: - Add the "BINARY" keyword when querying in MYSQL to force case sensitivity : select count(c_1) from table where BINARY c_1 = - - "aaa"; Or specify it when creating a table in MYSQL : CREATE TABLE table ( c_1 VARCHAR(255) CHARACTER SET binary ); - - Or specify collation rules to be case sensitive when initializing the MYSQL database : character-set-server=UTF-8 and - - collation-server=utf8_bin. + Add the "BINARY" keyword to force case sensitivity when querying in MYSQL: select count(c_1) from table where BINARY c_1 = "aaa"; or specify when creating a table in MYSQL: + CREATE TABLE table ( c_1 VARCHAR(255) CHARACTER SET binary ); Or specify collation rules to make case sensitive when initializing the MYSQL database: + character-set-server=UTF-8 and collation-server=utf8_bin. -10. There is a communication link exception in reading SQLServer +8. Communication link abnormality occurs when reading SQL Server ``` ERROR 1105 (HY000): errCode = 2, detailMessage = (10.16.10.6)[CANCELLED][INTERNAL_ERROR]UdfRuntimeException: Initialize datasource failed: @@ -793,26 +785,16 @@ DROP CATALOG ; unable to find valid certification path to requested target". ClientConnectionId:a92f3817-e8e6-4311-bc21-7c66 ``` - In the create Catalog `jdbc_url` the JDBC connection string finally increase `encrypt=false`, such as `"jdbc_url" = "jdbc:sqlserver://127.0.0.1:1433;DataBaseName=doris_test;encrypt=false"` - -11. Error encountered when reading MySQL datetime type - - ``` - ERROR 1105 (HY000): errCode = 2, detailMessage = (10.16.10.6)[INTERNAL_ERROR]UdfRuntimeException: get next block failed: - CAUSED BY: SQLException: Zero date value prohibited - CAUSED BY: DataReadException: Zero date value prohibited - ``` + You can add `encrypt=false` to the end of the JDBC connection string when creating the Catalog, such as `"jdbc_url" = "jdbc:sqlserver://127.0.0.1:1433;DataBaseName=doris_test;encrypt=false"` - This happens because JDBC can't handle the datetime format 0000-00-00 00:00:00. - To address this, append zeroDateTimeBehavior=convertToNull to the jdbc_url when creating the Catalog, e.g., "jdbc_url" = "jdbc:mysql://127.0.0.1:3306/test?zeroDateTimeBehavior=convertToNull". - In this case, JDBC will convert 0000-00-00 00:00:00 to null, and then Doris will handle the DateTime column as a nullable type, allowing for successful reading. +9. `Non supported character set (add orai18n.jar in your classpath): ZHS16GBK` exception occurs when reading Oracle -12. `Non supported character set (add orai18n.jar in your classpath): ZHS16GBK` exception occurs when reading Oracle + Download [orai18n.jar](https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html) and put it in the lib directory of Doris FE and the lib/java_extensions directory of BE (versions before Doris 2.0 It needs to be placed in the lib directory of BE). - Download [orai18n.jar](https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html) and put it in the lib directory of Doris FE and the `lib/java_extensions/` directory of BE (Doris versions before 2.0 need to be placed in the lib directory of BE). + Starting from version 2.0.2, this file can be placed in the `custom_lib/` directory of FE and BE (if it does not exist, just create it manually) to prevent the file from being lost when the lib directory is replaced when upgrading the cluster. - Starting from version 2.0.2, this file can be placed in BE's `custom_lib/` directory (if it does not exist, just create it manually) to prevent the file from being lost due to the replacement of the lib directory when upgrading the cluster. +10. `NoClassDefFoundError: net/jpountz/lz4/LZ4Factory` error message appears when reading Clickhouse data through jdbc catalog -13. `NoClassDefFoundError: net/jpountz/lz4/LZ4Factory` exception occurs when reading Clickhouse data via jdbc catalog. + You can download the [lz4-1.3.0.jar](https://repo1.maven.org/maven2/net/jpountz/lz4/lz4/1.3.0/lz4-1.3.0.jar) package first, and then put it in DorisFE lib directory and BE's `lib/lib/java_extensions` directory (versions before Doris 2.0 need to be placed in BE's lib directory). - You can download the [lz4-1.3.0.jar](https://repo1.maven.org/maven2/net/jpountz/lz4/lz4/1.3.0/lz4-1.3.0.jar) package and put it into the DorisFE `lib` directory and the `lib/java_extensions` directory of BE (the version before Doris 2.0 should be put into the `lib` directory of BE). + Starting from version 2.0.2, this file can be placed in the `custom_lib/` directory of FE and BE (if it does not exist, just create it manually) to prevent the file from being lost due to the replacement of the lib directory when upgrading the cluster. \ No newline at end of file diff --git a/docs/zh-CN/docs/lakehouse/multi-catalog/jdbc.md b/docs/zh-CN/docs/lakehouse/multi-catalog/jdbc.md index ec3a37ab4275a6..2896b5c410a180 100644 --- a/docs/zh-CN/docs/lakehouse/multi-catalog/jdbc.md +++ b/docs/zh-CN/docs/lakehouse/multi-catalog/jdbc.md @@ -696,13 +696,20 @@ DROP CATALOG ; SET NAMES utf8mb4 ``` -3. 读 MySQL 外表时,DateTime="0000:00:00 00:00:00"异常报错: "CAUSED BY: DataReadException: Zero date value prohibited" +3. 读取 MySQL date/datetime 类型出现异常 + + ``` + ERROR 1105 (HY000): errCode = 2, detailMessage = (10.16.10.6)[INTERNAL_ERROR]UdfRuntimeException: get next block failed: + CAUSED BY: SQLException: Zero date value prohibited + CAUSED BY: DataReadException: Zero date value prohibited + ``` + + 这是因为JDBC中对于该非法的 Date/DateTime 默认处理为抛出异常,可以通过参数 `zeroDateTimeBehavior`控制该行为。 - 这是因为JDBC中对于该非法的DateTime默认处理为抛出异常,可以通过参数 `zeroDateTimeBehavior`控制该行为。 - 可选参数为: `EXCEPTION`,`CONVERT_TO_NULL`,`ROUND`, 分别为:异常报错,转为NULL值,转为 "0001-01-01 00:00:00"; - - 可在url中添加: `"jdbc_url"="jdbc:mysql://IP:PORT/doris_test?zeroDateTimeBehavior=convertToNull"` + + 需要在创建 Catalog 的 `jdbc_url` 把JDBC连接串最后增加 `zeroDateTimeBehavior=convertToNull` ,如 `"jdbc_url" = "jdbc:mysql://127.0.0.1:3306/test?zeroDateTimeBehavior=convertToNull"` + 这种情况下,JDBC 会把 0000-00-00 或者 0000-00-00 00:00:00 转换成 null,然后 Doris 会把当前 Catalog 的所有 Date/DateTime 类型的列按照可空类型处理,这样就可以正常读取了。 4. 读取 MySQL 外表或其他外表时,出现加载类失败 @@ -741,16 +748,7 @@ DROP CATALOG ; 可在创建 Catalog 的 `jdbc_url` 把JDBC连接串最后增加 `?useSSL=false` ,如 `"jdbc_url" = "jdbc:mysql://127.0.0.1:3306/test?useSSL=false"` -6. 查询MYSQL的数据库报OutOfMemoryError的错误 - - 为减少内存的使用,在获取结果集时,每次仅获取batchSize的大小,这样一批一批的获取结果。而MYSQL默认是一次将结果全部加载到内存, - 设置的按批获取无法生效,需要主动显示的在URL中指定:"jdbc_url"="jdbc:mysql://IP:PORT/doris_test?useCursorFetch=true" - -7. 在使用JDBC查询过程中时,如果出现"CAUSED BY: SQLException OutOfMemoryError" 类似的错误 - - 如果MYSQL已经主动设置useCursorFetch,可以在be.conf中修改jvm_max_heap_size的值,尝试增大JVM的内存,目前默认值为1024M。 - -8. 使用JDBC查询MYSQL大数据量时,如果查询偶尔能够成功,偶尔会报如下错误,且出现该错误时MYSQL的连接被全部断开,无法连接到MYSQL SERVER,过段时间后mysql又恢复正常,但是之前的连接都没了: +6. 使用JDBC查询MYSQL大数据量时,如果查询偶尔能够成功,偶尔会报如下错误,且出现该错误时MYSQL的连接被全部断开,无法连接到MYSQL SERVER,过段时间后mysql又恢复正常,但是之前的连接都没了: ``` ERROR 1105 (HY000): errCode = 2, detailMessage = [INTERNAL_ERROR]UdfRuntimeException: JDBC executor sql has error: @@ -760,7 +758,7 @@ DROP CATALOG ; 出现上述现象时,可能是Mysql Server自身的内存或CPU资源被耗尽导致Mysql服务不可用,可以尝试增大Mysql Server的内存或CPU配置。 -9. 使用JDBC查询MYSQL的过程中,如果发现和在MYSQL库的查询结果不一致的情况 +7. 使用JDBC查询MYSQL的过程中,如果发现和在MYSQL库的查询结果不一致的情况 首先要先排查下查询字段中是字符串否存在有大小写情况。比如,Table中有一个字段c_1中有"aaa"和"AAA"两条数据,如果在初始化MYSQL数据库时未指定区分字符串 大小写,那么MYSQL默认是不区分字符串大小写的,但是在Doris中是严格区分大小写的,所以会出现以下情况: @@ -779,7 +777,7 @@ DROP CATALOG ; CREATE TABLE table ( c_1 VARCHAR(255) CHARACTER SET binary ); 或者在初始化MYSQL数据库时指定校对规则来区分大小写: character-set-server=UTF-8 和 collation-server=utf8_bin。 -10. 读取 SQLServer 出现通信链路异常 +8. 读取 SQLServer 出现通信链路异常 ``` ERROR 1105 (HY000): errCode = 2, detailMessage = (10.16.10.6)[CANCELLED][INTERNAL_ERROR]UdfRuntimeException: Initialize datasource failed: @@ -790,24 +788,14 @@ DROP CATALOG ; 可在创建 Catalog 的 `jdbc_url` 把JDBC连接串最后增加 `encrypt=false` ,如 `"jdbc_url" = "jdbc:sqlserver://127.0.0.1:1433;DataBaseName=doris_test;encrypt=false"` -11. 读取 MySQL datetime 类型出现异常 - - ``` - ERROR 1105 (HY000): errCode = 2, detailMessage = (10.16.10.6)[INTERNAL_ERROR]UdfRuntimeException: get next block failed: - CAUSED BY: SQLException: Zero date value prohibited - CAUSED BY: DataReadException: Zero date value prohibited - ``` - - 这是因为 JDBC 并不能处理 0000-00-00 00:00:00 这种时间格式, - 需要在创建 Catalog 的 `jdbc_url` 把JDBC连接串最后增加 `zeroDateTimeBehavior=convertToNull` ,如 `"jdbc_url" = "jdbc:mysql://127.0.0.1:3306/test?zeroDateTimeBehavior=convertToNull"` - 这种情况下,JDBC 会把 0000-00-00 00:00:00 转换成 null,然后 Doris 会把 DateTime 类型的列按照可空类型处理,这样就可以正常读取了。 - -12. 读取 Oracle 出现 `Non supported character set (add orai18n.jar in your classpath): ZHS16GBK` 异常 +9. 读取 Oracle 出现 `Non supported character set (add orai18n.jar in your classpath): ZHS16GBK` 异常 下载 [orai18n.jar](https://www.oracle.com/database/technologies/appdev/jdbc-downloads.html) 并放到 Doris FE 的 lib 目录以及 BE 的 lib/java_extensions 目录 (Doris 2.0 之前的版本需放到 BE 的 lib 目录下) 下即可。 - 从 2.0.2 版本起,可以将这个文件放置在BE的 `custom_lib/` 目录下(如不存在,手动创建即可),以防止升级集群时因为 lib 目录被替换而导致文件丢失。 + 从 2.0.2 版本起,可以将这个文件放置在 FE 和 BE 的 `custom_lib/` 目录下(如不存在,手动创建即可),以防止升级集群时因为 lib 目录被替换而导致文件丢失。 -13. 通过jdbc catalog 读取Clickhouse数据出现`NoClassDefFoundError: net/jpountz/lz4/LZ4Factory` 错误信息 +10. 通过jdbc catalog 读取Clickhouse数据出现`NoClassDefFoundError: net/jpountz/lz4/LZ4Factory` 错误信息 可以先下载[lz4-1.3.0.jar](https://repo1.maven.org/maven2/net/jpountz/lz4/lz4/1.3.0/lz4-1.3.0.jar)包,然后放到DorisFE lib 目录以及BE 的 `lib/lib/java_extensions`目录中(Doris 2.0 之前的版本需放到 BE 的 lib 目录下)。 + + 从 2.0.2 版本起,可以将这个文件放置在 FE 和 BE 的 `custom_lib/` 目录下(如不存在,手动创建即可),以防止升级集群时因为 lib 目录被替换而导致文件丢失。 \ No newline at end of file diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java index cb06722a05dbd9..61ba2a0db47d07 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/jdbc/client/JdbcMySQLClient.java @@ -265,6 +265,9 @@ protected Type jdbcTypeToDoris(JdbcFieldSchema fieldSchema) { case "BIGINT": return Type.BIGINT; case "DATE": + if (convertDateToNull) { + fieldSchema.setAllowNull(true); + } return ScalarType.createDateV2Type(); case "TIMESTAMP": case "DATETIME": { diff --git a/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out b/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out index d5cc90fa80f0d0..8fef1684317884 100644 --- a/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out +++ b/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out @@ -238,6 +238,10 @@ VIEWS \N 2023-06-17T10:00 +-- !test_dz -- +1 \N +2 2022-01-01 + -- !test_insert1 -- doris1 18 diff --git a/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_catalog.groovy b/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_catalog.groovy index d004d392377df7..6c68260857d7c6 100644 --- a/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_catalog.groovy +++ b/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_catalog.groovy @@ -59,6 +59,7 @@ suite("test_mysql_jdbc_catalog", "p0,external,mysql,external_docker,external_doc String auto_default_t = "auto_default_t"; String dt = "dt"; String dt_null = "dt_null"; + String test_zd = "test_zd" try_sql("DROP USER ${user}") sql """CREATE USER '${user}' IDENTIFIED BY '${pwd}'""" @@ -119,6 +120,7 @@ suite("test_mysql_jdbc_catalog", "p0,external,mysql,external_docker,external_doc order_qt_auto_default_t """insert into ${auto_default_t}(name) values('a'); """ order_qt_dt """select * from ${dt}; """ order_qt_dt_null """select * from ${dt_null} order by 1; """ + order_qt_test_dz """select * from ${test_zd} order by 1; """ // test insert String uuid1 = UUID.randomUUID().toString(); From a6f9df7096998093ead85703326e98639c0fea6e Mon Sep 17 00:00:00 2001 From: HappenLee Date: Wed, 8 Nov 2023 21:52:21 +0800 Subject: [PATCH 61/88] [LOG] Add fatal log in exchange sink buffer (#26594) --- be/src/pipeline/exec/exchange_sink_buffer.cpp | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/be/src/pipeline/exec/exchange_sink_buffer.cpp b/be/src/pipeline/exec/exchange_sink_buffer.cpp index f450fa69605fd4..4f93a39caa6929 100644 --- a/be/src/pipeline/exec/exchange_sink_buffer.cpp +++ b/be/src/pipeline/exec/exchange_sink_buffer.cpp @@ -369,12 +369,24 @@ void ExchangeSinkBuffer::_construct_request(InstanceLoId id, PUniqueId f template void ExchangeSinkBuffer::_ended(InstanceLoId id) { - std::unique_lock lock(*_instance_to_package_queue_mutex[id]); - if (!_rpc_channel_is_idle[id]) { - _busy_channels--; - _rpc_channel_is_idle[id] = true; - if (_finish_dependency && _busy_channels == 0) { - _finish_dependency->set_ready_to_finish(); + if (!_instance_to_package_queue_mutex.template contains(id)) { + std::stringstream ss; + ss << "failed find the instance id:" << id + << " now mutex map size:" << _instance_to_package_queue_mutex.size(); + for (const auto& p : _instance_to_package_queue_mutex) { + ss << " key:" << p.first << " value:" << p.second << "\n"; + } + LOG(INFO) << ss.str(); + + LOG(FATAL) << "not find the instance id"; + } else { + std::unique_lock lock(*_instance_to_package_queue_mutex[id]); + if (!_rpc_channel_is_idle[id]) { + _busy_channels--; + _rpc_channel_is_idle[id] = true; + if (_finish_dependency && _busy_channels == 0) { + _finish_dependency->set_ready_to_finish(); + } } } } From e92d2fcb5a7477be0ddd71ac0aa7143322a08aa3 Mon Sep 17 00:00:00 2001 From: meiyi Date: Wed, 8 Nov 2023 22:10:06 +0800 Subject: [PATCH 62/88] [improvement](group commit) Group commit insert into can be executed on observer fe (#26589) --- .../apache/doris/analysis/NativeInsertStmt.java | 16 +++++++++++++--- .../java/org/apache/doris/qe/StmtExecutor.java | 4 ++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/analysis/NativeInsertStmt.java b/fe/fe-core/src/main/java/org/apache/doris/analysis/NativeInsertStmt.java index 1837c268915a11..219c9b9373782d 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/analysis/NativeInsertStmt.java +++ b/fe/fe-core/src/main/java/org/apache/doris/analysis/NativeInsertStmt.java @@ -365,7 +365,7 @@ public void analyze(Analyzer analyzer) throws UserException { analyzeTargetTable(analyzer); db = analyzer.getEnv().getCatalogMgr().getCatalog(tblName.getCtl()).getDbOrAnalysisException(tblName.getDb()); - analyzeGroupCommit(); + analyzeGroupCommit(analyzer); if (isGroupCommit()) { return; } @@ -1067,14 +1067,24 @@ protected void resetPrepare() { @Override public RedirectStatus getRedirectStatus() { - if (isExplain()) { + if (isExplain() || isGroupCommit()) { return RedirectStatus.NO_FORWARD; } else { return RedirectStatus.FORWARD_WITH_SYNC; } } - private void analyzeGroupCommit() { + public void analyzeGroupCommit(Analyzer analyzer) { + if (isGroupCommit) { + return; + } + try { + tblName.analyze(analyzer); + initTargetTable(analyzer); + } catch (Throwable e) { + LOG.warn("analyze group commit failed", e); + return; + } if (ConnectContext.get().getSessionVariable().enableInsertGroupCommit && targetTable instanceof OlapTable && !ConnectContext.get().isTxnModel() diff --git a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java index 8eaff7fdf107cf..49a3e45608580f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java +++ b/fe/fe-core/src/main/java/org/apache/doris/qe/StmtExecutor.java @@ -1109,6 +1109,10 @@ private void parseByLegacy() throws AnalysisException, DdlException { analyzeVariablesInStmt(); } + if (context.getSessionVariable().enableInsertGroupCommit && parsedStmt instanceof NativeInsertStmt) { + NativeInsertStmt nativeInsertStmt = (NativeInsertStmt) parsedStmt; + nativeInsertStmt.analyzeGroupCommit(new Analyzer(context.getEnv(), context)); + } redirectStatus = parsedStmt.getRedirectStatus(); } From b7a2c2e9c4c0ebbce2a69bbb6b797b604cfe91d0 Mon Sep 17 00:00:00 2001 From: AlexYue Date: Wed, 8 Nov 2023 22:14:54 +0800 Subject: [PATCH 63/88] [chore](regression) Do stale resource reclaim before executing cold heat separation p2 case(#26596) --- .../cold_heat_separation_p2/load.groovy | 52 +++++++++++++++++++ .../table_modify_resouce_and_policy.groovy | 4 +- 2 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 regression-test/suites/cold_heat_separation_p2/load.groovy diff --git a/regression-test/suites/cold_heat_separation_p2/load.groovy b/regression-test/suites/cold_heat_separation_p2/load.groovy new file mode 100644 index 00000000000000..25509500c97b55 --- /dev/null +++ b/regression-test/suites/cold_heat_separation_p2/load.groovy @@ -0,0 +1,52 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +import groovy.json.JsonSlurper +import org.codehaus.groovy.runtime.IOGroovyMethods + +suite("cold_heat_separation", "p2") { + try_sql """ + drop database regression_test_cold_heat_separation_p2 force; + """ + + try_sql """ + create database regression_test_cold_heat_separation_p2; + """ + + def polices = sql """ + show storage policy; + """ + + for (policy in polices) { + if (policy[3].equals("STORAGE")) { + try_sql """ + drop storage policy if exists ${policy[0]} + """ + } + } + + def resources = sql """ + show resources; + """ + + for (resource in resources) { + if (resource[1].equals("s3")) { + try_sql """ + drop resource if exists ${resource[0]} + """ + } + } +} \ No newline at end of file diff --git a/regression-test/suites/cold_heat_separation_p2/table_modify_resouce_and_policy.groovy b/regression-test/suites/cold_heat_separation_p2/table_modify_resouce_and_policy.groovy index bc9a518799ea1b..79b78834f8c0ef 100644 --- a/regression-test/suites/cold_heat_separation_p2/table_modify_resouce_and_policy.groovy +++ b/regression-test/suites/cold_heat_separation_p2/table_modify_resouce_and_policy.groovy @@ -234,7 +234,7 @@ suite("table_modify_resouce") { log.info( "test all remote size not zero") for (int i = 0; i < tablets2.size(); i++) { fetchDataSize(sizes, tablets2[i]) - assertEquals(sizes[1], tablets[i][9]) + assertTrue(sizes[1] > 0) } @@ -317,7 +317,7 @@ suite("table_modify_resouce") { log.info( "test all remote size not zero") for (int i = 0; i < tablets2.size(); i++) { fetchDataSize(sizes, tablets2[i]) - assertEquals(sizes[1], tablets[i][9]) + assertTrue(sizes[1] > 0) } From 8e332fa979e986260957d08b01d460e8821384bf Mon Sep 17 00:00:00 2001 From: walter Date: Wed, 8 Nov 2023 22:24:17 +0800 Subject: [PATCH 64/88] (selectdb-cloud) Reduce FE db lock range for ShowDataStmt (#26588) Reduce read lock critical sections and avoid execution timeouts --- .../org/apache/doris/catalog/Database.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java index 74b8608760c86b..62d2e0bd6d6e56 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/Database.java @@ -274,24 +274,23 @@ public void setDbProperties(DatabaseProperty dbProperties) { public long getUsedDataQuotaWithLock() { long usedDataQuota = 0; readLock(); - try { - for (Table table : this.idToTable.values()) { - if (table.getType() != TableType.OLAP) { - continue; - } + List tables = new ArrayList<>(this.idToTable.values()); + readUnlock(); - OlapTable olapTable = (OlapTable) table; - olapTable.readLock(); - try { - usedDataQuota = usedDataQuota + olapTable.getDataSize(); - } finally { - olapTable.readUnlock(); - } + for (Table table : tables) { + if (table.getType() != TableType.OLAP) { + continue; + } + + OlapTable olapTable = (OlapTable) table; + olapTable.readLock(); + try { + usedDataQuota = usedDataQuota + olapTable.getDataSize(); + } finally { + olapTable.readUnlock(); } - return usedDataQuota; - } finally { - readUnlock(); } + return usedDataQuota; } public long getReplicaCountWithLock() { From ee6e6911dadbf50bc54f4be4318127c39a0fc03b Mon Sep 17 00:00:00 2001 From: Guangdong Liu Date: Wed, 8 Nov 2023 22:28:30 +0800 Subject: [PATCH 65/88] [regression-test](stream load) Invalid merge type check (#26599) --- .../load_p0/stream_load/test_stream_load.groovy | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/regression-test/suites/load_p0/stream_load/test_stream_load.groovy b/regression-test/suites/load_p0/stream_load/test_stream_load.groovy index 8f4801e9cfe20d..b0626a5cbb5aff 100644 --- a/regression-test/suites/load_p0/stream_load/test_stream_load.groovy +++ b/regression-test/suites/load_p0/stream_load/test_stream_load.groovy @@ -977,6 +977,20 @@ suite("test_stream_load", "p0") { assertEquals(0, json.NumberUnselectedRows) } } + + streamLoad { + table "${tableName14}" + set 'merge_type', 'other' + file 'test_default_value.csv' + check { result, exception, startTime, endTime -> + if (exception != null) { + throw exception + } + log.info("Stream load result: ${result}".toString()) + def json = parseJson(result) + assertEquals("[INVALID_ARGUMENT]Invalid merge type other", json.Message) + } + } sql "sync" def res = sql "select * from ${tableName14}" From b3ae7f04f9b034ea7460f78b9f0e08a7ce37ede5 Mon Sep 17 00:00:00 2001 From: walter Date: Wed, 8 Nov 2023 22:28:49 +0800 Subject: [PATCH 66/88] [fix](backup) Add repo id to local meta/info files to avoid overwriting (#26536) The local meta/info files generated during backup are not distinguished by repo names. If two backup jobs with the same name are submitted to different repos at the same time, meta/info may be overwritten by another backup job. --- .../org/apache/doris/backup/BackupJob.java | 5 +- .../org/apache/doris/backup/Repository.java | 18 ++- ...kup_restore_diff_repo_same_snapshot.groovy | 133 ++++++++++++++++++ 3 files changed, 148 insertions(+), 8 deletions(-) create mode 100644 regression-test/suites/backup_restore/test_backup_restore_diff_repo_same_snapshot.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java b/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java index e60e9e300b1d58..1d730db184946b 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/backup/BackupJob.java @@ -664,9 +664,10 @@ private void waitingAllUploadingFinished() { private void saveMetaInfo() { String createTimeStr = TimeUtils.longToTimeString(createTime, TimeUtils.DATETIME_FORMAT_WITH_HYPHEN); - // local job dir: backup/label__createtime/ + // local job dir: backup/repo__repo_id/label__createtime/ + // Add repo_id to isolate jobs from different repos. localJobDirPath = Paths.get(BackupHandler.BACKUP_ROOT_DIR.toString(), - label + "__" + createTimeStr).normalize(); + "repo__" + repoId, label + "__" + createTimeStr).normalize(); try { // 1. create local job dir of this backup job diff --git a/fe/fe-core/src/main/java/org/apache/doris/backup/Repository.java b/fe/fe-core/src/main/java/org/apache/doris/backup/Repository.java index 27ce489948aa11..a95b6a953aa69f 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/backup/Repository.java +++ b/fe/fe-core/src/main/java/org/apache/doris/backup/Repository.java @@ -59,6 +59,7 @@ import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; +import java.util.UUID; /* * Repository represents a remote storage for backup to or restore from @@ -251,7 +252,7 @@ public Status initRepository() { } // exist, download and parse the repo info file - String localFilePath = BackupHandler.BACKUP_ROOT_DIR + "/tmp_info_" + System.currentTimeMillis(); + String localFilePath = BackupHandler.BACKUP_ROOT_DIR + "/tmp_info_" + allocLocalFileSuffix(); try { st = fileSystem.downloadWithFileSize(repoInfoFilePath, localFilePath, remoteFile.getSize()); if (!st.ok()) { @@ -419,7 +420,7 @@ public String assembleRemoteSnapshotPath(String label, SnapshotInfo info) { public Status getSnapshotInfoFile(String label, String backupTimestamp, List infos) { String remoteInfoFilePath = assembleJobInfoFilePath(label, -1) + backupTimestamp; File localInfoFile = new File(BackupHandler.BACKUP_ROOT_DIR + PATH_DELIMITER - + "info_" + System.currentTimeMillis()); + + "info_" + allocLocalFileSuffix()); try { Status st = download(remoteInfoFilePath, localInfoFile.getPath()); if (!st.ok()) { @@ -441,7 +442,7 @@ public Status getSnapshotInfoFile(String label, String backupTimestamp, List backupMetas, int metaVersion) { String remoteMetaFilePath = assembleMetaInfoFilePath(label); File localMetaFile = new File(BackupHandler.BACKUP_ROOT_DIR + PATH_DELIMITER - + "meta_" + System.currentTimeMillis()); + + "meta_" + allocLocalFileSuffix()); try { Status st = download(remoteMetaFilePath, localMetaFile.getAbsolutePath()); @@ -732,9 +733,9 @@ private List getSnapshotInfo(String snapshotName, String timestamp) { } } } else { - // get specified timestamp - // path eg: /path/to/backup/__info_2081-04-19-12-59-11 - String localFilePath = BackupHandler.BACKUP_ROOT_DIR + "/" + Repository.PREFIX_JOB_INFO + timestamp; + // get specified timestamp, different repos might have snapshots with same timestamp. + String localFilePath = BackupHandler.BACKUP_ROOT_DIR + "/" + + Repository.PREFIX_JOB_INFO + allocLocalFileSuffix(); try { String remoteInfoFilePath = assembleJobInfoFilePath(snapshotName, -1) + timestamp; Status st = download(remoteInfoFilePath, localFilePath); @@ -772,6 +773,11 @@ private List getSnapshotInfo(String snapshotName, String timestamp) { return info; } + // Allocate an unique suffix. + private String allocLocalFileSuffix() { + return System.currentTimeMillis() + UUID.randomUUID().toString().replace("-", "_"); + } + @Override public void write(DataOutput out) throws IOException { out.writeLong(id); diff --git a/regression-test/suites/backup_restore/test_backup_restore_diff_repo_same_snapshot.groovy b/regression-test/suites/backup_restore/test_backup_restore_diff_repo_same_snapshot.groovy new file mode 100644 index 00000000000000..19e2e2fd048238 --- /dev/null +++ b/regression-test/suites/backup_restore/test_backup_restore_diff_repo_same_snapshot.groovy @@ -0,0 +1,133 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_backup_restore_diff_repo_same_snapshot", "backup_restore") { + String suiteName = "test_backup_restore_diff_repo_same_snapshot" + String repoName = "${suiteName}_repo" + String dbName = "${suiteName}_db" + String tableName = "${suiteName}_table" + String snapshotName = "${suiteName}_snapshot" + + def syncer = getSyncer() + syncer.createS3Repository("${repoName}_1") + syncer.createS3Repository("${repoName}_2") + + sql "CREATE DATABASE IF NOT EXISTS ${dbName}_1" + sql "CREATE DATABASE IF NOT EXISTS ${dbName}_2" + sql "DROP TABLE IF EXISTS ${dbName}_1.${tableName}_1" + sql "DROP TABLE IF EXISTS ${dbName}_2.${tableName}_2" + sql """ + CREATE TABLE ${dbName}_1.${tableName}_1 ( + `id` LARGEINT NOT NULL, + `count` LARGEINT SUM DEFAULT "0") + AGGREGATE KEY(`id`) + DISTRIBUTED BY HASH(`id`) BUCKETS 2 + PROPERTIES ( "replication_num" = "1") + """ + sql """ + CREATE TABLE ${dbName}_2.${tableName}_2 ( + `id` LARGEINT NOT NULL, + `count` LARGEINT SUM DEFAULT "0") + AGGREGATE KEY(`id`) + DISTRIBUTED BY HASH(`id`) BUCKETS 2 + PROPERTIES ( "replication_num" = "1" ) + """ + + List values = [] + for (int i = 1; i <= 10; ++i) { + values.add("(${i}, ${i})") + } + sql "INSERT INTO ${dbName}_1.${tableName}_1 VALUES ${values.join(",")}" + sql "INSERT INTO ${dbName}_2.${tableName}_2 VALUES ${values.join(",")}" + def result = sql "SELECT * FROM ${dbName}_1.${tableName}_1" + assertEquals(result.size(), values.size()); + result = sql "SELECT * FROM ${dbName}_2.${tableName}_2" + assertEquals(result.size(), values.size()); + + // Backup to different repo, with same snapshot name. + sql """ + BACKUP SNAPSHOT ${dbName}_1.${snapshotName} + TO `${repoName}_1` + ON (${tableName}_1) + """ + sql """ + BACKUP SNAPSHOT ${dbName}_2.${snapshotName} + TO `${repoName}_2` + ON (${tableName}_2) + """ + + while (!syncer.checkSnapshotFinish("${dbName}_1")) { + Thread.sleep(3000) + } + while (!syncer.checkSnapshotFinish("${dbName}_2")) { + Thread.sleep(3000) + } + + // Restore snapshot from repo_1 to db_1 + def snapshot = syncer.getSnapshotTimestamp("${repoName}_1", snapshotName) + assertTrue(snapshot != null) + + sql "TRUNCATE TABLE ${dbName}_1.${tableName}_1" + sql """ + RESTORE SNAPSHOT ${dbName}_1.${snapshotName} + FROM `${repoName}_1` + ON ( `${tableName}_1`) + PROPERTIES + ( + "backup_timestamp" = "${snapshot}", + "replication_num" = "1" + ) + """ + + while (!syncer.checkAllRestoreFinish("${dbName}_1")) { + Thread.sleep(3000) + } + + result = sql "SELECT * FROM ${dbName}_1.${tableName}_1" + assertEquals(result.size(), values.size()); + + // Restore snapshot from repo_2 to db_2 + snapshot = syncer.getSnapshotTimestamp("${repoName}_2", snapshotName) + assertTrue(snapshot != null) + + sql "TRUNCATE TABLE ${dbName}_2.${tableName}_2" + sql """ + RESTORE SNAPSHOT ${dbName}_2.${snapshotName} + FROM `${repoName}_2` + ON ( `${tableName}_2`) + PROPERTIES + ( + "backup_timestamp" = "${snapshot}", + "replication_num" = "1" + ) + """ + + while (!syncer.checkAllRestoreFinish("${dbName}_2")) { + Thread.sleep(3000) + } + + result = sql "SELECT * FROM ${dbName}_2.${tableName}_2" + assertEquals(result.size(), values.size()); + + sql "DROP TABLE ${dbName}_1.${tableName}_1 FORCE" + sql "DROP TABLE ${dbName}_2.${tableName}_2 FORCE" + sql "DROP DATABASE ${dbName}_1 FORCE" + sql "DROP DATABASE ${dbName}_2 FORCE" + sql "DROP REPOSITORY `${repoName}_1`" + sql "DROP REPOSITORY `${repoName}_2`" +} + From 18b3d0ec6bdd44b34dc11440945ab3ad84d9d122 Mon Sep 17 00:00:00 2001 From: lw112 <131352377+felixwluo@users.noreply.github.com> Date: Wed, 8 Nov 2023 22:29:34 +0800 Subject: [PATCH 67/88] =?UTF-8?q?[cases](regression-test)=20add=20unique?= =?UTF-8?q?=20and=20duplicate=20backup=20and=20restore=20=E2=80=A6=20(#264?= =?UTF-8?q?91)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * [cases](regression-test) add unique and duplicate backup and restore table models * Add delete and mor scenes --- .../test_duplicate_backup_restore.groovy | 123 ++++++++++++++++++ .../test_unique_backup_restore.groovy | 123 ++++++++++++++++++ 2 files changed, 246 insertions(+) create mode 100644 regression-test/suites/backup_restore/test_duplicate_backup_restore.groovy create mode 100644 regression-test/suites/backup_restore/test_unique_backup_restore.groovy diff --git a/regression-test/suites/backup_restore/test_duplicate_backup_restore.groovy b/regression-test/suites/backup_restore/test_duplicate_backup_restore.groovy new file mode 100644 index 00000000000000..a3117feb30eb72 --- /dev/null +++ b/regression-test/suites/backup_restore/test_duplicate_backup_restore.groovy @@ -0,0 +1,123 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_duplicate_backup_restore", "backup_restore") { + String repoName = "test_duplicate_backup_restore_repo" + String dbName = "duplicate_backup_restore_db" + String tableName = "test_duplicate_backup_restore_table" + + def syncer = getSyncer() + syncer.createS3Repository(repoName) + + sql "CREATE DATABASE IF NOT EXISTS ${dbName}" + sql "DROP TABLE IF EXISTS ${dbName}.${tableName}" + sql """ + CREATE TABLE ${dbName}.${tableName} ( + `id` LARGEINT NOT NULL, + `count` LARGEINT NOT NULL DEFAULT "0") + DUPLICATE KEY(`id`) + DISTRIBUTED BY HASH(`id`) BUCKETS 1 + PROPERTIES + ( + "replication_num" = "1" + ) + """ + + List values = [] + for (int i = 1; i <= 10; ++i) { + values.add("(${i}, ${i})") + } + sql "INSERT INTO ${dbName}.${tableName} VALUES ${values.join(",")}" + sql "INSERT INTO ${dbName}.${tableName} VALUES (1,1),(2,2),(3,3),(1,1),(2,2)" + def result = sql "SELECT * FROM ${dbName}.${tableName}" + assertEquals(result.size(), values.size() + 5); + + String snapshotName = "test_duplicate_backup_restore" + sql """ + BACKUP SNAPSHOT ${dbName}.${snapshotName} + TO `${repoName}` + ON (${tableName}) + PROPERTIES ("type" = "full") + """ + + while (!syncer.checkSnapshotFinish(dbName)) { + Thread.sleep(3000) + } + + def snapshot = syncer.getSnapshotTimestamp(repoName, snapshotName) + assertTrue(snapshot != null) + sql "TRUNCATE TABLE ${dbName}.${tableName}" + + sql """ + RESTORE SNAPSHOT ${dbName}.${snapshotName} + FROM `${repoName}` + ON ( `${tableName}`) + PROPERTIES + ( + "backup_timestamp" = "${snapshot}", + "replication_num" = "1" + ) + """ + + while (!syncer.checkAllRestoreFinish(dbName)) { + Thread.sleep(3000) + } + + result = sql "SELECT * FROM ${dbName}.${tableName}" + assertEquals(result.size(), values.size() + 5); + + sql "DROP REPOSITORY `${repoName}`" + + sql "DELETE FROM ${dbName}.${tableName} WHERE id = 1" + result = sql "SELECT * FROM ${dbName}.${tableName}" + assertEquals(result.size(), values.size() + 5 - 3) + repoName = "test_duplicate_delete_backup_restore_repo" + syncer.createS3Repository(repoName) + snapshotName = "test_duplicate_delete_backup_restore_snapshot" + sql """ + BACKUP SNAPSHOT ${dbName}.${snapshotName} + TO `${repoName}` + ON (${tableName}) + PROPERTIES ("type" = "full") + """ + + while (!syncer.checkSnapshotFinish(dbName)) { + Thread.sleep(3000) + } + + snapshot = syncer.getSnapshotTimestamp(repoName, snapshotName) + assertTrue(snapshot != null) + sql "TRUNCATE TABLE ${dbName}.${tableName}" + sql """ + RESTORE SNAPSHOT ${dbName}.${snapshotName} + FROM `${repoName}` + ON ( `${tableName}`) + PROPERTIES + ( + "backup_timestamp" = "${snapshot}", + "replication_num" = "1" + ) + """ + while (!syncer.checkAllRestoreFinish(dbName)) { + Thread.sleep(3000) + } + result = sql "SELECT * FROM ${dbName}.${tableName}" + assertEquals(result.size(), values.size() + 5 - 3) + sql "DROP TABLE ${dbName}.${tableName} FORCE" + sql "DROP DATABASE ${dbName} FORCE" + sql "DROP REPOSITORY `${repoName}`" +} diff --git a/regression-test/suites/backup_restore/test_unique_backup_restore.groovy b/regression-test/suites/backup_restore/test_unique_backup_restore.groovy new file mode 100644 index 00000000000000..b1092871fd9641 --- /dev/null +++ b/regression-test/suites/backup_restore/test_unique_backup_restore.groovy @@ -0,0 +1,123 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_unique_backup_restore", "backup_restore") { + String repoName = "test_unique_backup_restore_repo" + String dbName = "unique_backup_restore_db" + String tableName = "test_unique_backup_restore_table" + + def syncer = getSyncer() + syncer.createS3Repository(repoName) + + sql "CREATE DATABASE IF NOT EXISTS ${dbName}" + sql "DROP TABLE IF EXISTS ${dbName}.${tableName}" + sql """ + CREATE TABLE ${dbName}.${tableName} ( + `id` LARGEINT NOT NULL, + `count` LARGEINT NOT NULL DEFAULT "0") + UNIQUE KEY(`id`) + DISTRIBUTED BY HASH(`id`) BUCKETS 1 + PROPERTIES + ( + "replication_num" = "1", + "enable_unique_key_merge_on_write" = "true" + ) + """ + + // version1 (1,1)(2,2) + sql """INSERT INTO ${dbName}.${tableName} VALUES (1,1),(2,2)""" + def result = sql"SELECT * FROM ${dbName}.${tableName} ORDER BY id" + assertEquals(result.size(), 2) + + // version2 (1,5)(2,2) + sql "INSERT INTO ${dbName}.${tableName} VALUES (1,5)" + + String snapshotName = "test_unique_backup_restore_snapshot" + sql """ + BACKUP SNAPSHOT ${dbName}.${snapshotName} + TO `${repoName}` + ON (${tableName}) + PROPERTIES ("type" = "full") + """ + + while (!syncer.checkSnapshotFinish(dbName)) { + Thread.sleep(3000) + } + + def snapshot = syncer.getSnapshotTimestamp(repoName, snapshotName) + assertTrue(snapshot != null) + + sql "TRUNCATE TABLE ${dbName}.${tableName}" + sql """ + RESTORE SNAPSHOT ${dbName}.${snapshotName} + FROM `${repoName}` + ON ( `${tableName}`) + PROPERTIES + ( + "backup_timestamp" = "${snapshot}", + "replication_num" = "1" + ) + """ + + while (!syncer.checkAllRestoreFinish(dbName)) { + Thread.sleep(3000) + } + + result = sql "SELECT * FROM ${dbName}.${tableName}" + assertEquals(result.size(), 2) + + sql "DROP REPOSITORY `${repoName}`" + + sql "DELETE FROM ${dbName}.${tableName} WHERE id = 1" + result = sql "SELECT * FROM ${dbName}.${tableName}" + assertEquals(result.size(), 1) + repoName = "test_unique_delete_backup_restore_repo" + syncer.createS3Repository(repoName) + snapshotName = "test_unique_delete_backup_restore_snapshot" + sql """ + BACKUP SNAPSHOT ${dbName}.${snapshotName} + TO `${repoName}` + ON (${tableName}) + PROPERTIES ("type" = "full") + """ + + while (!syncer.checkSnapshotFinish(dbName)) { + Thread.sleep(3000) + } + + snapshot = syncer.getSnapshotTimestamp(repoName, snapshotName) + assertTrue(snapshot != null) + sql "TRUNCATE TABLE ${dbName}.${tableName}" + sql """ + RESTORE SNAPSHOT ${dbName}.${snapshotName} + FROM `${repoName}` + ON ( `${tableName}`) + PROPERTIES + ( + "backup_timestamp" = "${snapshot}", + "replication_num" = "1" + ) + """ + while (!syncer.checkAllRestoreFinish(dbName)) { + Thread.sleep(3000) + } + result = sql "SELECT * FROM ${dbName}.${tableName}" + assertEquals(result.size(), 1) + sql "DROP TABLE ${dbName}.${tableName} FORCE" + sql "DROP DATABASE ${dbName} FORCE" + sql "DROP REPOSITORY `${repoName}`" +} \ No newline at end of file From 9c828ff79c6f483ef3d3a4baa5874d53cedb0791 Mon Sep 17 00:00:00 2001 From: Changming Xiao Date: Wed, 8 Nov 2023 22:30:01 +0800 Subject: [PATCH 68/88] [cases](regression-test) Add backup & restore test case of dup table (#26490) Co-authored-by: Bears0haunt --- ...up_restore_dup_without_default_keys.groovy | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 regression-test/suites/backup_restore/test_backup_restore_dup_without_default_keys.groovy diff --git a/regression-test/suites/backup_restore/test_backup_restore_dup_without_default_keys.groovy b/regression-test/suites/backup_restore/test_backup_restore_dup_without_default_keys.groovy new file mode 100644 index 00000000000000..0266e73eaa2c55 --- /dev/null +++ b/regression-test/suites/backup_restore/test_backup_restore_dup_without_default_keys.groovy @@ -0,0 +1,84 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_backup_restore_dup_without_default_keys", "backup_restore") { + String repoName = "test_backup_restore_dup_without_default_keys_repo" + String dbName = "backup_restore_dup_without_default_keys_db" + String tableName = "dup_without_keys_table" + + // backup & restore for duplicate without keys by default + def syncer = getSyncer() + syncer.createS3Repository(repoName) + + sql "CREATE DATABASE IF NOT EXISTS ${dbName}" + sql "DROP TABLE IF EXISTS ${dbName}.${tableName}" + sql """ + CREATE TABLE ${dbName}.${tableName} ( + `id` LARGEINT NOT NULL, + `count` LARGEINT) + DISTRIBUTED BY HASH(`id`) BUCKETS 2 + PROPERTIES + ( + "replication_num" = "1", + "enable_duplicate_without_keys_by_default" = "true" + ) + """ + + List values = [] + for(int i = 1;i <= 10; ++i){ + values.add("(${i}, ${i})") + } + sql "INSERT INTO ${dbName}.${tableName} VALUES ${values.join(",")}" + + def result = sql "SELECT * FROM ${dbName}.${tableName}" + assertEquals(result.size(),values.size()) + + String snapshotName = "test_backup_restore_dup_without_default_keys_snapshot" + sql """ + BACKUP SNAPSHOT ${dbName}.${snapshotName} + TO `${repoName}` + ON (${tableName}) + """ + + while (!syncer.checkSnapshotFinish(dbName)) { + Thread.sleep(3000) + } + def snapshot = syncer.getSnapshotTimestamp(repoName, snapshotName) + assertTrue(snapshot != null) + + sql "TRUNCATE TABLE ${dbName}.${tableName}" + + sql """ + RESTORE SNAPSHOT ${dbName}.${snapshotName} + FROM `${repoName}` + ON (`${tableName}`) + PROPERTIES + ( + "backup_timestamp" = "${snapshot}", + "replication_num" = "1" + ) + """ + while (!syncer.checkAllRestoreFinish(dbName)) { + Thread.sleep(3000) + } + result = sql "SELECT * FROM ${dbName}.${tableName}" + assertEquals(result.size(), values.size()); + + sql "DROP TABLE ${dbName}.${tableName} FORCE" + sql "DROP DATABASE ${dbName} FORCE" + sql "DROP REPOSITORY `${repoName}`" +} \ No newline at end of file From faaf0ecc851beb5847e7ec6dabfcab4f8090117c Mon Sep 17 00:00:00 2001 From: shuke <37901441+shuke987@users.noreply.github.com> Date: Wed, 8 Nov 2023 23:42:53 +0800 Subject: [PATCH 69/88] [regression-test](framework) Support running tests multiple times and reporting correctly to TeamCity (#26606) --- .../doris/regression/RegressionTest.groovy | 21 +++++++++++++++- .../doris/regression/util/Recorder.groovy | 4 +++ .../regression/util/TeamcityUtils.groovy | 25 +++++++++++++++---- 3 files changed, 44 insertions(+), 6 deletions(-) diff --git a/regression-test/framework/src/main/groovy/org/apache/doris/regression/RegressionTest.groovy b/regression-test/framework/src/main/groovy/org/apache/doris/regression/RegressionTest.groovy index 6cdb918a7f4666..36850b8ab10a6b 100644 --- a/regression-test/framework/src/main/groovy/org/apache/doris/regression/RegressionTest.groovy +++ b/regression-test/framework/src/main/groovy/org/apache/doris/regression/RegressionTest.groovy @@ -30,6 +30,7 @@ import org.apache.doris.regression.suite.event.StackEventListeners import org.apache.doris.regression.suite.SuiteScript import org.apache.doris.regression.suite.event.TeamcityEventListener import org.apache.doris.regression.util.Recorder +import org.apache.doris.regression.util.TeamcityUtils import groovy.util.logging.Slf4j import org.apache.commons.cli.* import org.apache.commons.lang3.concurrent.BasicThreadFactory; @@ -65,10 +66,28 @@ class RegressionTest { Config config = Config.fromCommandLine(cmd) initGroovyEnv(config) boolean success = true + Integer totalFailure = 0 + Integer failureLimit = Integer.valueOf(config.otherConfigs.getOrDefault("max_failure_num", "-1").toString()) + if (failureLimit <= 0) { + failureLimit = Integer.MAX_VALUE + } + for (int i = 0; i < config.times; i++) { log.info("=== run ${i} time ===") + if (config.times > 1) { + TeamcityUtils.postfix = i.toString() + } + Recorder recorder = runScripts(config) - success = printResult(config, recorder) + success = (success && printResult(config, recorder)) + + if (recorder.getFatalNum() > 0) { + break + } + totalFailure += recorder.getFailureOrFatalNum() + if (totalFailure > failureLimit) { + break + } } actionExecutors.shutdown() suiteExecutors.shutdown() diff --git a/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/Recorder.groovy b/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/Recorder.groovy index 25bbd524c6bfc1..6a0ee19334ef00 100644 --- a/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/Recorder.groovy +++ b/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/Recorder.groovy @@ -45,6 +45,10 @@ class Recorder { return failureCounter.get() } + public int getFatalNum() { + return fatalScriptList.size() + } + void onSuccess(SuiteInfo suiteInfo) { successList.add(suiteInfo) } diff --git a/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/TeamcityUtils.groovy b/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/TeamcityUtils.groovy index dd713db2d1db25..61e6ff2eed3140 100644 --- a/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/TeamcityUtils.groovy +++ b/regression-test/framework/src/main/groovy/org/apache/doris/regression/util/TeamcityUtils.groovy @@ -24,34 +24,49 @@ import org.apache.tools.ant.util.DateUtils @CompileStatic class TeamcityUtils { + static String postfix = "" + + static String getSuiteName(String name) { + if (postfix == "") { + return name + } else { + return name+"-"+postfix + } + } + static String formatNow() { return DateUtils.format(System.currentTimeMillis(), "yyyy-MM-dd'T'HH:mm:ss.SSSZ") } static String formatStdOut(SuiteContext suiteContext, String msg) { String timestamp = formatNow() - return "##teamcity[testStdOut name='${suiteContext.flowName}' out='${escape(msg)}' flowId='${suiteContext.flowId}' timestamp='${timestamp}']" + String name = getSuiteName(suiteContext.flowName) + return "##teamcity[testStdOut name='${name}' out='${escape(msg)}' flowId='${suiteContext.flowId}' timestamp='${timestamp}']" } static String formatStdErr(SuiteContext suiteContext, String msg) { String timestamp = formatNow() - return "##teamcity[testStdErr name='${suiteContext.flowName}' out='${escape(msg)}' flowId='${suiteContext.flowId}' timestamp='${timestamp}']" + String name = getSuiteName(suiteContext.flowName) + return "##teamcity[testStdErr name='${name}' out='${escape(msg)}' flowId='${suiteContext.flowId}' timestamp='${timestamp}']" } static void testStarted(SuiteContext suiteContext) { String timestamp = formatNow() + String name = getSuiteName(suiteContext.flowName) println("##teamcity[flowStarted flowId='${suiteContext.flowId}' timestamp='${timestamp}']") - println("##teamcity[testStarted name='${suiteContext.flowName}' flowId='${suiteContext.flowId}' timestamp='${timestamp}']") + println("##teamcity[testStarted name='${name}' flowId='${suiteContext.flowId}' timestamp='${timestamp}']") } static void testFailed(SuiteContext suiteContext, String msg, String details) { String timestamp = formatNow() - println("##teamcity[testFailed name='${suiteContext.flowName}' message='${escape(msg)}' flowId='${suiteContext.flowId}' details='${escape(details)}' timestamp='${timestamp}']") + String name = getSuiteName(suiteContext.flowName) + println("##teamcity[testFailed name='${name}' message='${escape(msg)}' flowId='${suiteContext.flowId}' details='${escape(details)}' timestamp='${timestamp}']") } static void testFinished(SuiteContext suiteContext, long elapsed) { String timestamp = formatNow() - println("##teamcity[testFinished name='${suiteContext.flowName}' flowId='${suiteContext.flowId}' duration='${elapsed}' timestamp='${timestamp}']") + String name = getSuiteName(suiteContext.flowName) + println("##teamcity[testFinished name='${name}' flowId='${suiteContext.flowId}' duration='${elapsed}' timestamp='${timestamp}']") println("##teamcity[flowFinished flowId='${suiteContext.flowId}' timestamp='${timestamp}']") } From 55b2988bfde2f55df50f36d6c9c2d50f819c576b Mon Sep 17 00:00:00 2001 From: zhiqiang Date: Wed, 8 Nov 2023 18:46:51 -0600 Subject: [PATCH 70/88] [Opt](date_add/sub) Throw exception when result of date_add/sub out of range (#26475) --- .../function_date_or_datetime_computation.h | 39 ++- ..._date_or_datetime_computation_negative.out | 91 ++++++ ...te_or_datetime_computation_negative.groovy | 276 ++++++++++++++++++ 3 files changed, 400 insertions(+), 6 deletions(-) create mode 100644 regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_or_datetime_computation_negative.out create mode 100644 regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_or_datetime_computation_negative.groovy diff --git a/be/src/vec/functions/function_date_or_datetime_computation.h b/be/src/vec/functions/function_date_or_datetime_computation.h index a4d230180dbaf4..3d0e0a8fd4aabc 100644 --- a/be/src/vec/functions/function_date_or_datetime_computation.h +++ b/be/src/vec/functions/function_date_or_datetime_computation.h @@ -27,6 +27,8 @@ #include #include +#include "common/compiler_util.h" +#include "common/exception.h" #include "common/logging.h" #include "common/status.h" #include "fmt/format.h" @@ -400,7 +402,11 @@ struct DateTimeOp { // otherwise it will be implicitly converted to bool, causing the rvalue to fail to match the lvalue. // the same goes for the following. vec_to[i] = Transform::execute(vec_from0[i], vec_from1[i], invalid); - DCHECK(!invalid); + + if (UNLIKELY(invalid)) { + throw Exception(ErrorCode::OUT_OF_BOUND, "Operation {} {} {} out of range", + Transform::name, vec_from0[i], vec_from1[i]); + } } } @@ -425,7 +431,11 @@ struct DateTimeOp { bool invalid = true; for (size_t i = 0; i < size; ++i) { vec_to[i] = Transform::execute(vec_from0[i], vec_from1[i], invalid); - DCHECK(!invalid); + + if (UNLIKELY(invalid)) { + throw Exception(ErrorCode::OUT_OF_BOUND, "Operation {} {} {} out of range", + Transform::name, vec_from0[i], vec_from1[i]); + } } } @@ -449,7 +459,11 @@ struct DateTimeOp { bool invalid = true; for (size_t i = 0; i < size; ++i) { vec_to[i] = Transform::execute(vec_from[i], delta, invalid); - DCHECK(!invalid); + + if (UNLIKELY(invalid)) { + throw Exception(ErrorCode::OUT_OF_BOUND, "Operation {} {} {} out of range", + Transform::name, vec_from[i], delta); + } } } @@ -473,7 +487,11 @@ struct DateTimeOp { for (size_t i = 0; i < size; ++i) { vec_to[i] = Transform::execute(vec_from[i], delta, invalid); - DCHECK(!invalid); + + if (UNLIKELY(invalid)) { + throw Exception(ErrorCode::OUT_OF_BOUND, "Operation {} {} {} out of range", + Transform::name, vec_from[i], delta); + } } } @@ -497,7 +515,11 @@ struct DateTimeOp { for (size_t i = 0; i < size; ++i) { vec_to[i] = Transform::execute(from, delta.get_int(i), invalid); - DCHECK(!invalid); + + if (UNLIKELY(invalid)) { + throw Exception(ErrorCode::OUT_OF_BOUND, "Operation {} {} {} out of range", + Transform::name, from, delta.get_int(i)); + } } } @@ -511,6 +533,7 @@ struct DateTimeOp { vec_to[i] = Transform::execute(from, delta[i], reinterpret_cast(null_map[i])); } } + static void constant_vector(const FromType1& from, PaddedPODArray& vec_to, const PaddedPODArray& delta) { size_t size = delta.size(); @@ -519,7 +542,11 @@ struct DateTimeOp { for (size_t i = 0; i < size; ++i) { vec_to[i] = Transform::execute(from, delta[i], invalid); - DCHECK(!invalid); + + if (UNLIKELY(invalid)) { + throw Exception(ErrorCode::OUT_OF_BOUND, "Operation {} {} {} out of range", + Transform::name, from, delta[i]); + } } } }; diff --git a/regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_or_datetime_computation_negative.out b/regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_or_datetime_computation_negative.out new file mode 100644 index 00000000000000..9a3dd1db9ccbcd --- /dev/null +++ b/regression-test/data/nereids_p0/sql_functions/datetime_functions/test_date_or_datetime_computation_negative.out @@ -0,0 +1,91 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select_nullable_1 -- +\N \N \N +\N \N \N +9998-12-31 9998-12-31 9998-12-31T23:59:59 +\N \N \N + +-- !select_nullable_2 -- +\N \N \N +\N \N \N +9999-11-30 9999-11-30 9999-11-30T23:59:59 +\N \N \N + +-- !select_nullable_3 -- +\N \N \N +\N \N \N +9999-12-24 9999-12-24 9999-12-24T23:59:59 +\N \N \N + +-- !select_nullable_4 -- +\N \N \N +\N \N \N +9999-12-30 9999-12-30 9999-12-30T23:59:59 +\N \N \N + +-- !select_nullable_5 -- +\N \N \N +\N \N \N +9999-12-30T23:00 9999-12-30T23:00 9999-12-31T22:59:59 +\N \N \N + +-- !select_nullable_6 -- +\N \N \N +\N \N \N +9999-12-30T23:59 9999-12-30T23:59 9999-12-31T23:58:59 +\N \N \N + +-- !select_nullable_7 -- +\N \N \N +\N \N \N +9999-12-30T23:59:59 9999-12-30T23:59:59 9999-12-31T23:59:58 +\N \N \N + +-- !select_nullable_8 -- +0001-01-01 0001-01-01 0001-01-01T00:00 +\N \N \N +\N \N \N +\N \N \N + +-- !select_nullable_9 -- +0000-02-01 0000-02-01 0000-02-01T00:00 +\N \N \N +\N \N \N +\N \N \N + +-- !select_nullable_10 -- +0000-01-08 0000-01-08 0000-01-08T00:00 +\N \N \N +\N \N \N +\N \N \N + +-- !select_nullable_11 -- +0000-01-02 0000-01-02 0000-01-02T00:00 +\N \N \N +\N \N \N +\N \N \N + +-- !select_nullable_12 -- +0000-01-01T01:00 0000-01-01T01:00 0000-01-01T01:00 +\N \N \N +9999-12-31T01:00 9999-12-31T01:00 \N +\N \N \N + +-- !select_nullable_13 -- +0000-01-01T00:01 0000-01-01T00:01 0000-01-01T00:01 +\N \N \N +9999-12-31T00:01 9999-12-31T00:01 \N +\N \N \N + +-- !select_nullable_14 -- +0000-01-01T00:00:01 0000-01-01T00:00:01 0000-01-01T00:00:01 +\N \N \N +9999-12-31T00:00:01 9999-12-31T00:00:01 \N +\N \N \N + +-- !select_nullable_15 -- +0000-01-02T00:00 0000-01-02T00:00 0000-01-02T00:00 +\N \N \N +\N \N \N +\N \N \N + diff --git a/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_or_datetime_computation_negative.groovy b/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_or_datetime_computation_negative.groovy new file mode 100644 index 00000000000000..83431ede6ab55d --- /dev/null +++ b/regression-test/suites/nereids_p0/sql_functions/datetime_functions/test_date_or_datetime_computation_negative.groovy @@ -0,0 +1,276 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +test_date_or_datetime_computation_negative +suite("test_date_or_datetime_computation_negative") { + sql """ CREATE TABLE IF NOT EXISTS test_date_or_datetime_computation_negative ( + `row_id` LARGEINT NOT NULL, + `date` DATE NOT NULL, + `date_null` DATE NULL, + `dateV2` DATEV2 NOT NULL, + `dateV2_null` DATEV2 NULL, + `datetime` DATETIME NOT NULL, + `datetime_null` DATETIME NULL, ) + DUPLICATE KEY(`row_id`) + DISTRIBUTED BY HASH(`row_id`) BUCKETS 1 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + );""" + + sql "set enable_insert_strict = false;" + sql "set parallel_fragment_exec_instance_num = 3;" + sql "set enable_nereids_planner = true;" + + sql """INSERT INTO test_date_or_datetime_computation_negative VALUES (1, '0000-01-01', '0000-01-01', '0000-01-01', '0000-01-01', '0000-01-01 00:00:00', '0000-01-01 00:00:00');""" + sql """INSERT INTO test_date_or_datetime_computation_negative VALUES (2, '0000-01-01', NULL, '0000-01-01', NULL, '0000-01-01 00:00:00', NULL);""" + sql """INSERT INTO test_date_or_datetime_computation_negative VALUES (3, '9999-12-31', '9999-12-31', '9999-12-31', '9999-12-31', '9999-12-31 23:59:59', '9999-12-31 23:59:59');""" + sql """INSERT INTO test_date_or_datetime_computation_negative VALUES (4, '9999-12-31', NULL, '9999-12-31', NULL, '9999-12-31 23:59:59', NULL);""" + + test { + sql """SELECT date_sub(date, interval 1 year) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(dateV2, interval 1 year) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(datetime, interval 1 year) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + qt_select_nullable_1 """SELECT date_sub(date_null, interval 1 year), date_sub(dateV2_null, interval 1 year), date_sub(datetime_null, interval 1 year) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """SELECT date_sub(date, interval 1 month) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(dateV2, interval 1 month) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(datetime, interval 1 month) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + qt_select_nullable_2 """SELECT date_sub(date_null, interval 1 month), date_sub(dateV2_null, interval 1 month), date_sub(datetime_null, interval 1 month) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """ SELECT date_sub(date, interval 1 week) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """ SELECT date_sub(dateV2, interval 1 week) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """ SELECT date_sub(datetime, interval 1 week) FROM test_date_or_datetime_computation_negative WHERE row_id=1; """ + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + + qt_select_nullable_3 """SELECT date_sub(date_null, interval 1 week), date_sub(dateV2_null, interval 1 week), date_sub(datetime_null, interval 1 week) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """SELECT date_sub(date, interval 1 day) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(dateV2, interval 1 day) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(datetime, interval 1 day) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + + qt_select_nullable_4 """SELECT date_sub(date_null, interval 1 day), date_sub(dateV2_null, interval 1 day), date_sub(datetime_null, interval 1 day) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """SELECT date_sub(date, interval 1 hour) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(dateV2, interval 1 hour) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(datetime, interval 1 hour) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + qt_select_nullable_5 """ SELECT date_sub(date_null, interval 1 hour), date_sub(dateV2_null, interval 1 hour), date_sub(datetime_null, interval 1 hour) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """SELECT date_sub(date, interval 1 minute) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(dateV2, interval 1 minute) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(datetime, interval 1 minute) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + qt_select_nullable_6 """SELECT date_sub(date_null, interval 1 minute), date_sub(dateV2_null, interval 1 minute), date_sub(datetime_null, interval 1 minute) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """SELECT date_sub(date, interval 1 second) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(dateV2, interval 1 second) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_sub(datetime, interval 1 second) FROM test_date_or_datetime_computation_negative WHERE row_id=1;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + qt_select_nullable_7 """SELECT date_sub(date_null, interval 1 second), date_sub(dateV2_null, interval 1 second), date_sub(datetime_null, interval 1 second) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + + test { + sql """SELECT date_add(date, interval 1 year) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(dateV2, interval 1 year) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(datetime, interval 1 year) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + qt_select_nullable_8 """SELECT date_add(date_null, interval 1 year), date_add(dateV2_null, interval 1 year), date_add(datetime_null, interval 1 year) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """SELECT date_add(date, interval 1 month) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(dateV2, interval 1 month) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(datetime, interval 1 month) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + qt_select_nullable_9 """SELECT date_add(date_null, interval 1 month), date_add(dateV2_null, interval 1 month), date_add(datetime_null, interval 1 month) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """ SELECT date_add(date, interval 1 week) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """ SELECT date_add(dateV2, interval 1 week) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """ SELECT date_add(datetime, interval 1 week) FROM test_date_or_datetime_computation_negative WHERE row_id=3; """ + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + + qt_select_nullable_10 """SELECT date_add(date_null, interval 1 week), date_add(dateV2_null, interval 1 week), date_add(datetime_null, interval 1 week) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """SELECT date_add(date, interval 1 day) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(dateV2, interval 1 day) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(datetime, interval 1 day) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + + qt_select_nullable_11 """SELECT date_add(date_null, interval 1 day), date_add(dateV2_null, interval 1 day), date_add(datetime_null, interval 1 day) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """SELECT date_add(date, interval 1 hour) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(dateV2, interval 1 hour) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(datetime, interval 1 hour) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + qt_select_nullable_12 """ SELECT date_add(date_null, interval 1 hour), date_add(dateV2_null, interval 1 hour), date_add(datetime_null, interval 1 hour) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """SELECT date_add(date, interval 1 minute) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(dateV2, interval 1 minute) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(datetime, interval 1 minute) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + qt_select_nullable_13 """SELECT date_add(date_null, interval 1 minute), date_add(dateV2_null, interval 1 minute), date_add(datetime_null, interval 1 minute) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + test { + sql """SELECT date_add(date, interval 1 second) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(dateV2, interval 1 second) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT date_add(datetime, interval 1 second) FROM test_date_or_datetime_computation_negative WHERE row_id=3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + qt_select_nullable_14 """SELECT date_add(date_null, interval 1 second), date_add(dateV2_null, interval 1 second), date_add(datetime_null, interval 1 second) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + // TODO: + // nagetive test for microseconds_add/milliseconds_add/seconds_add/minutes_add/hours_add/days_add/weeks_add/months_add/years_add + + test { + sql """SELECT hours_add(date, 24) FROM test_date_or_datetime_computation_negative WHERE row_id = 3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT hours_add(dateV2, 24) FROM test_date_or_datetime_computation_negative WHERE row_id = 3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + + sql """SELECT hours_add(datetime, 24) FROM test_date_or_datetime_computation_negative WHERE row_id = 3;""" + check {result, exception, startTime, endTime -> + assertTrue (exception != null)} + } + qt_select_nullable_15 """SELECT hours_add(date_null, 24), hours_add(dateV2_null, 24), hours_add(datetime_null, 24) FROM test_date_or_datetime_computation_negative ORDER BY row_id;""" + + sql "DROP TABLE test_date_or_datetime_computation_negative" +} From 66e591f7f25464b51f43ab4c57f9889b6afb44eb Mon Sep 17 00:00:00 2001 From: yiguolei <676222867@qq.com> Date: Thu, 9 Nov 2023 08:50:42 +0800 Subject: [PATCH 71/88] [enhancement](brpc) add a auto release closure to ensure the closue safety (#26567) --- be/src/olap/delta_writer.cpp | 56 +++++++++++------------ be/src/util/ref_count_closure.h | 81 +++++++++++++++++++++++++++++++++ 2 files changed, 107 insertions(+), 30 deletions(-) diff --git a/be/src/olap/delta_writer.cpp b/be/src/olap/delta_writer.cpp index 23e1718cb7d3ca..3e91e5efb060b6 100644 --- a/be/src/olap/delta_writer.cpp +++ b/be/src/olap/delta_writer.cpp @@ -243,21 +243,20 @@ void DeltaWriter::_request_slave_tablet_pull_rowset(PNodeInfo node_info) { } } - PTabletWriteSlaveRequest request; - RowsetMetaPB rowset_meta_pb = cur_rowset->rowset_meta()->get_rowset_pb(); - request.set_allocated_rowset_meta(&rowset_meta_pb); - request.set_host(BackendOptions::get_localhost()); - request.set_http_port(config::webserver_port); + auto request = std::make_shared(); + *(request->mutable_rowset_meta()) = cur_rowset->rowset_meta()->get_rowset_pb(); + request->set_host(BackendOptions::get_localhost()); + request->set_http_port(config::webserver_port); string tablet_path = _rowset_builder.tablet()->tablet_path(); - request.set_rowset_path(tablet_path); - request.set_token(ExecEnv::GetInstance()->token()); - request.set_brpc_port(config::brpc_port); - request.set_node_id(node_info.id()); + request->set_rowset_path(tablet_path); + request->set_token(ExecEnv::GetInstance()->token()); + request->set_brpc_port(config::brpc_port); + request->set_node_id(node_info.id()); for (int segment_id = 0; segment_id < cur_rowset->rowset_meta()->num_segments(); segment_id++) { std::stringstream segment_name; segment_name << cur_rowset->rowset_id() << "_" << segment_id << ".dat"; int64_t segment_size = std::filesystem::file_size(tablet_path + "/" + segment_name.str()); - request.mutable_segments_size()->insert({segment_id, segment_size}); + request->mutable_segments_size()->insert({segment_id, segment_size}); if (!indices_ids.empty()) { for (auto index_id : indices_ids) { @@ -269,41 +268,38 @@ void DeltaWriter::_request_slave_tablet_pull_rowset(PNodeInfo node_info) { index_size.set_size(size); // Fetch the map value for the current segment_id. // If it doesn't exist, this will insert a new default-constructed IndexSizeMapValue - auto& index_size_map_value = (*request.mutable_inverted_indices_size())[segment_id]; + auto& index_size_map_value = + (*(request->mutable_inverted_indices_size()))[segment_id]; // Add the new index size to the map value. *index_size_map_value.mutable_index_sizes()->Add() = std::move(index_size); } } } - RefCountClosure* closure = - new RefCountClosure(); - closure->ref(); - closure->ref(); - closure->cntl.set_timeout_ms(config::slave_replica_writer_rpc_timeout_sec * 1000); - closure->cntl.ignore_eovercrowded(); - stub->request_slave_tablet_pull_rowset(&closure->cntl, &request, &closure->result, closure); - static_cast(request.release_rowset_meta()); - - closure->join(); - if (closure->cntl.Failed()) { + + auto pull_callback = DummyBrpcCallback::create_shared(); + auto closure = AutoReleaseClosure< + PTabletWriteSlaveRequest, + DummyBrpcCallback>::create_unique(request, pull_callback); + closure->cntl_->set_timeout_ms(config::slave_replica_writer_rpc_timeout_sec * 1000); + closure->cntl_->ignore_eovercrowded(); + stub->request_slave_tablet_pull_rowset(closure->cntl_.get(), closure->request_.get(), + closure->response_.get(), closure.release()); + + pull_callback->join(); + if (pull_callback->cntl_->Failed()) { if (!ExecEnv::GetInstance()->brpc_internal_client_cache()->available( stub, node_info.host(), node_info.async_internal_port())) { ExecEnv::GetInstance()->brpc_internal_client_cache()->erase( - closure->cntl.remote_side()); + pull_callback->cntl_->remote_side()); } LOG(WARNING) << "failed to send pull rowset request to slave replica, error=" - << berror(closure->cntl.ErrorCode()) - << ", error_text=" << closure->cntl.ErrorText() + << berror(pull_callback->cntl_->ErrorCode()) + << ", error_text=" << pull_callback->cntl_->ErrorText() << ". slave host: " << node_info.host() << ", tablet_id=" << _req.tablet_id << ", txn_id=" << _req.txn_id; std::lock_guard lock(_slave_node_lock); _unfinished_slave_node.erase(node_info.id()); } - - if (closure->unref()) { - delete closure; - } - closure = nullptr; } void DeltaWriter::finish_slave_tablet_pull_rowset(int64_t node_id, bool is_succeed) { diff --git a/be/src/util/ref_count_closure.h b/be/src/util/ref_count_closure.h index d2fbd2fd14e863..d844a7fc820b90 100644 --- a/be/src/util/ref_count_closure.h +++ b/be/src/util/ref_count_closure.h @@ -54,4 +54,85 @@ class RefCountClosure : public google::protobuf::Closure { std::atomic _refs; }; +template +class DummyBrpcCallback { + ENABLE_FACTORY_CREATOR(DummyBrpcCallback); + +public: + using ResponseType = Response; + DummyBrpcCallback() { + cntl_ = std::make_shared(); + response_ = std::make_shared(); + } + + void call() {} + + void join() { brpc::Join(cntl_->call_id()); } + + // controller has to be the same lifecycle with the closure, because brpc may use + // it in any stage of the rpc. + std::shared_ptr cntl_; + // We do not know if brpc will use request or response after brpc method returns. + // So that we need keep a shared ptr here to ensure that brpc could use req/rep + // at any stage. + std::shared_ptr response_; +}; + +// The closure will be deleted after callback. +// It could only be created by using shared ptr or unique ptr. +// It will hold a weak ptr of T and call run of T +// Callback() { +// xxxx; +// public +// void run() { +// logxxx +// } +// } +// +// std::shared_ptr b; +// +// std::unique_ptr a(b); +// brpc_call(a.release()); + +template +class AutoReleaseClosure : public google::protobuf::Closure { + using Weak = typename std::shared_ptr::weak_type; + using ResponseType = typename Callback::ResponseType; + ENABLE_FACTORY_CREATOR(AutoReleaseClosure); + +public: + AutoReleaseClosure(std::shared_ptr req, std::shared_ptr callback) + : callback_(callback) { + this->cntl_ = callback->cntl_; + this->response_ = callback->response_; + } + + ~AutoReleaseClosure() override = default; + + // Will delete itself + void Run() override { + SCOPED_TRACK_MEMORY_TO_UNKNOWN(); + Defer defer {[&]() { delete this; }}; + // If lock failed, it means the callback object is deconstructed, then no need + // to deal with the callback any more. + if (auto tmp = callback_.lock()) { + tmp->call(); + } + } + + // controller has to be the same lifecycle with the closure, because brpc may use + // it in any stage of the rpc. + std::shared_ptr cntl_; + // We do not know if brpc will use request or response after brpc method returns. + // So that we need keep a shared ptr here to ensure that brpc could use req/rep + // at any stage. + std::shared_ptr request_; + std::shared_ptr response_; + +private: + // Use a weak ptr to keep the callback, so that the callback can be deleted if the main + // thread is freed. + Weak callback_; +}; + } // namespace doris From 7df60a49806ccb901375329d9e47d4a6f12b22fc Mon Sep 17 00:00:00 2001 From: Tiewei Fang <43782773+BePPPower@users.noreply.github.com> Date: Thu, 9 Nov 2023 09:06:09 +0800 Subject: [PATCH 72/88] [Refactor](Tvf) delete some unused code of tvf and add doc for `queries` tvf (#26460) 1. delete some unused code of tvf 2. add doc for `queries` tvf: #25051 --- .../sql-functions/table-functions/queries.md | 79 +++++++++++++++++++ docs/sidebars.json | 5 +- .../sql-functions/table-functions/queries.md | 79 +++++++++++++++++++ .../org/apache/doris/load/ExportFailMsg.java | 13 --- .../java/org/apache/doris/load/ExportJob.java | 1 - .../ExternalFileTableValuedFunction.java | 15 ++-- .../HdfsTableValuedFunction.java | 1 - .../tablefunction/MetadataGenerator.java | 25 ------ 8 files changed, 168 insertions(+), 50 deletions(-) create mode 100644 docs/en/docs/sql-manual/sql-functions/table-functions/queries.md create mode 100644 docs/zh-CN/docs/sql-manual/sql-functions/table-functions/queries.md diff --git a/docs/en/docs/sql-manual/sql-functions/table-functions/queries.md b/docs/en/docs/sql-manual/sql-functions/table-functions/queries.md new file mode 100644 index 00000000000000..26527c39685d3a --- /dev/null +++ b/docs/en/docs/sql-manual/sql-functions/table-functions/queries.md @@ -0,0 +1,79 @@ +--- +{ + "title": "QUERIES", + "language": "en" +} +--- + + + +## `queries` + +### Name + + + +queries + + + +### description + +Table-Value-Function, generate a temporary table named queries. This tvf is used to view the information of running queries and history queries in doris cluster. + +This function is used in FROM clauses. + +#### syntax +`queries()` + +queries() table schema: +``` +mysql> desc function queries(); ++------------------+--------+------+-------+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------+--------+------+-------+---------+-------+ +| QueryId | TEXT | No | false | NULL | NONE | +| StartTime | BIGINT | No | false | NULL | NONE | +| EndTime | BIGINT | Yes | false | NULL | NONE | +| EventTime | BIGINT | Yes | false | NULL | NONE | +| Latency | BIGINT | No | false | NULL | NONE | +| State | TEXT | No | false | NULL | NONE | +| Database | TEXT | Yes | false | NULL | NONE | +| Sql | TEXT | No | false | NULL | NONE | +| FrontendInstance | TEXT | No | false | NULL | NONE | ++------------------+--------+------+-------+---------+-------+ +9 rows in set (0.00 sec) +``` + +### example +``` +mysql> select* from queries(); ++-----------------------------------+---------------+---------------+---------------+---------+----------+----------+------------------------+------------------+ +| QueryId | StartTime | EndTime | EventTime | Latency | State | Database | Sql | FrontendInstance | ++-----------------------------------+---------------+---------------+---------------+---------+----------+----------+------------------------+------------------+ +| e1293f2ed2a5427a-982301c462586043 | 1699255138730 | 1699255139823 | 1699255139823 | 1093 | FINISHED | demo | select* from queries() | localhost | +| 46fa3ad0e7814ebd-b1cd34940a29b1e9 | 1699255143588 | -1 | 1699255143588 | 20 | RUNNING | demo | select* from queries() | localhost | ++-----------------------------------+---------------+---------------+---------------+---------+----------+----------+------------------------+------------------+ +2 rows in set (0.04 sec) +``` + +### keywords + + queries diff --git a/docs/sidebars.json b/docs/sidebars.json index 9fd9cf97554d56..e436221e693dc3 100644 --- a/docs/sidebars.json +++ b/docs/sidebars.json @@ -749,7 +749,8 @@ "sql-manual/sql-functions/table-functions/frontends", "sql-manual/sql-functions/table-functions/workload-group", "sql-manual/sql-functions/table-functions/catalogs", - "sql-manual/sql-functions/table-functions/frontends_disks" + "sql-manual/sql-functions/table-functions/frontends_disks", + "sql-manual/sql-functions/table-functions/queries" ] }, { @@ -1342,4 +1343,4 @@ ] } ] -} +} \ No newline at end of file diff --git a/docs/zh-CN/docs/sql-manual/sql-functions/table-functions/queries.md b/docs/zh-CN/docs/sql-manual/sql-functions/table-functions/queries.md new file mode 100644 index 00000000000000..cdfd3e75fd2d25 --- /dev/null +++ b/docs/zh-CN/docs/sql-manual/sql-functions/table-functions/queries.md @@ -0,0 +1,79 @@ +--- +{ + "title": "QUERIES", + "language": "zh-CN" +} +--- + + + +## `queries` + +### Name + + + +queries + + + +### description + +表函数,生成queries临时表,可以查看当前doris集群中正在运行的以及历史的 query 信息。 + +该函数用于from子句中。 + +#### syntax +`queries()` + +queries()表结构: +``` +mysql> desc function queries(); ++------------------+--------+------+-------+---------+-------+ +| Field | Type | Null | Key | Default | Extra | ++------------------+--------+------+-------+---------+-------+ +| QueryId | TEXT | No | false | NULL | NONE | +| StartTime | BIGINT | No | false | NULL | NONE | +| EndTime | BIGINT | Yes | false | NULL | NONE | +| EventTime | BIGINT | Yes | false | NULL | NONE | +| Latency | BIGINT | No | false | NULL | NONE | +| State | TEXT | No | false | NULL | NONE | +| Database | TEXT | Yes | false | NULL | NONE | +| Sql | TEXT | No | false | NULL | NONE | +| FrontendInstance | TEXT | No | false | NULL | NONE | ++------------------+--------+------+-------+---------+-------+ +9 rows in set (0.00 sec) +``` + +### example +``` +mysql> select* from queries(); ++-----------------------------------+---------------+---------------+---------------+---------+----------+----------+------------------------+------------------+ +| QueryId | StartTime | EndTime | EventTime | Latency | State | Database | Sql | FrontendInstance | ++-----------------------------------+---------------+---------------+---------------+---------+----------+----------+------------------------+------------------+ +| e1293f2ed2a5427a-982301c462586043 | 1699255138730 | 1699255139823 | 1699255139823 | 1093 | FINISHED | demo | select* from queries() | localhost | +| 46fa3ad0e7814ebd-b1cd34940a29b1e9 | 1699255143588 | -1 | 1699255143588 | 20 | RUNNING | demo | select* from queries() | localhost | ++-----------------------------------+---------------+---------------+---------------+---------+----------+----------+------------------------+------------------+ +2 rows in set (0.04 sec) +``` + +### keywords + + queries diff --git a/fe/fe-core/src/main/java/org/apache/doris/load/ExportFailMsg.java b/fe/fe-core/src/main/java/org/apache/doris/load/ExportFailMsg.java index 591abe462d5d30..48df89400027ad 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/load/ExportFailMsg.java +++ b/fe/fe-core/src/main/java/org/apache/doris/load/ExportFailMsg.java @@ -40,11 +40,6 @@ public enum CancelType { @SerializedName("msg") private String msg; - public ExportFailMsg() { - this.cancelType = CancelType.UNKNOWN; - this.msg = ""; - } - public ExportFailMsg(CancelType cancelType, String msg) { this.cancelType = cancelType; this.msg = msg; @@ -54,18 +49,10 @@ public CancelType getCancelType() { return cancelType; } - public void setCancelType(CancelType cancelType) { - this.cancelType = cancelType; - } - public String getMsg() { return msg; } - public void setMsg(String msg) { - this.msg = msg; - } - @Override public String toString() { return "ExportFailMsg [cancelType=" + cancelType + ", msg=" + msg + "]"; diff --git a/fe/fe-core/src/main/java/org/apache/doris/load/ExportJob.java b/fe/fe-core/src/main/java/org/apache/doris/load/ExportJob.java index b0df62afb0d433..5d31053017d162 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/load/ExportJob.java +++ b/fe/fe-core/src/main/java/org/apache/doris/load/ExportJob.java @@ -227,7 +227,6 @@ public ExportJob(long jobId) { public void generateOutfileStatement() throws UserException { exportTable.readLock(); try { - // generateQueryStmtOld generateQueryStmt(); } finally { exportTable.readUnlock(); diff --git a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java index ffe6f7109a8f79..3569c4f447979a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/ExternalFileTableValuedFunction.java @@ -33,7 +33,6 @@ import org.apache.doris.catalog.Table; import org.apache.doris.catalog.Type; import org.apache.doris.common.AnalysisException; -import org.apache.doris.common.FeConstants; import org.apache.doris.common.Pair; import org.apache.doris.common.UserException; import org.apache.doris.common.util.BrokerUtil; @@ -311,13 +310,13 @@ public List getTableColumns() throws AnalysisException { if (!csvSchema.isEmpty()) { return csvSchema; } - if (FeConstants.runningUnitTest) { - Object mockedUtObj = FeConstants.unitTestConstant; - if (mockedUtObj instanceof List) { - return ((List) mockedUtObj); - } - return new ArrayList<>(); - } + // if (FeConstants.runningUnitTest) { + // Object mockedUtObj = FeConstants.unitTestConstant; + // if (mockedUtObj instanceof List) { + // return ((List) mockedUtObj); + // } + // return new ArrayList<>(); + // } if (this.columns != null) { return columns; } diff --git a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/HdfsTableValuedFunction.java b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/HdfsTableValuedFunction.java index 051706ae474a4d..dd85ec55a61dac 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/HdfsTableValuedFunction.java +++ b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/HdfsTableValuedFunction.java @@ -60,7 +60,6 @@ private void init(Map properties) throws AnalysisException { // 3. analyze other properties for (String key : otherProps.keySet()) { if (HdfsResource.HADOOP_FS_NAME.equalsIgnoreCase(key)) { - // because HADOOP_FS_NAME contains upper and lower case locationProperties.put(HdfsResource.HADOOP_FS_NAME, otherProps.get(key)); } else { locationProperties.put(key, otherProps.get(key)); diff --git a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java index 46443ca64a30c4..c38744ba35e1b7 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java +++ b/fe/fe-core/src/main/java/org/apache/doris/tablefunction/MetadataGenerator.java @@ -20,15 +20,12 @@ import org.apache.doris.catalog.Env; import org.apache.doris.common.AnalysisException; import org.apache.doris.common.ClientPool; -import org.apache.doris.common.MetaNotFoundException; import org.apache.doris.common.Pair; import org.apache.doris.common.UserException; import org.apache.doris.common.proc.FrontendsProcNode; import org.apache.doris.common.util.NetUtils; import org.apache.doris.common.util.TimeUtils; import org.apache.doris.datasource.CatalogIf; -import org.apache.doris.datasource.HMSExternalCatalog; -import org.apache.doris.datasource.property.constants.HMSProperties; import org.apache.doris.planner.external.iceberg.IcebergMetadataCache; import org.apache.doris.qe.ConnectContext; import org.apache.doris.qe.QueryDetail; @@ -55,10 +52,7 @@ import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.gson.Gson; -import org.apache.hadoop.conf.Configuration; -import org.apache.hadoop.hdfs.HdfsConfiguration; import org.apache.iceberg.Snapshot; -import org.apache.iceberg.catalog.TableIdentifier; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.thrift.TException; @@ -67,13 +61,10 @@ import java.time.Instant; import java.time.LocalDateTime; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; - - public class MetadataGenerator { private static final Logger LOG = LogManager.getLogger(MetadataGenerator.class); @@ -480,22 +471,6 @@ private static void filterColumns(TFetchSchemaTableDataResult result, result.setDataBatch(filterColumnsRows); } - private static org.apache.iceberg.Table getIcebergTable(HMSExternalCatalog catalog, String db, String tbl) - throws MetaNotFoundException { - org.apache.iceberg.hive.HiveCatalog hiveCatalog = new org.apache.iceberg.hive.HiveCatalog(); - Configuration conf = new HdfsConfiguration(); - Map properties = catalog.getCatalogProperty().getHadoopProperties(); - for (Map.Entry entry : properties.entrySet()) { - conf.set(entry.getKey(), entry.getValue()); - } - hiveCatalog.setConf(conf); - Map catalogProperties = new HashMap<>(); - catalogProperties.put(HMSProperties.HIVE_METASTORE_URIS, catalog.getHiveMetastoreUris()); - catalogProperties.put("uri", catalog.getHiveMetastoreUris()); - hiveCatalog.initialize("hive", catalogProperties); - return hiveCatalog.loadTable(TableIdentifier.of(db, tbl)); - } - private static long convertToDateTimeV2( int year, int month, int day, int hour, int minute, int second, int microsecond) { return (long) microsecond | (long) second << 20 | (long) minute << 26 | (long) hour << 32 From 74e452f19c52ff321d1222afea27459ad15ff993 Mon Sep 17 00:00:00 2001 From: zhangstar333 <87313068+zhangstar333@users.noreply.github.com> Date: Thu, 9 Nov 2023 10:05:09 +0800 Subject: [PATCH 73/88] [bug](bitmap) fix bitmap value copy operator not call reset (#26451) when a empty bitmap assign to other bitmap the other bitmap should reset self firstly, and then set empty type. --- be/src/util/bitmap_value.h | 29 +++--- .../aggregate_function_bitmap.h | 2 +- .../aggregate_function_bitmap_agg.h | 2 +- be/src/vec/data_types/data_type_bitmap.cpp | 4 +- be/src/vec/data_types/data_type_bitmap.h | 8 +- be/src/vec/functions/function_bitmap.cpp | 12 +-- be/test/util/bitmap_value_test.cpp | 44 ++++++++- .../aggregate_functions/agg_bitmap_test.cpp | 92 +++++++++++++++++++ 8 files changed, 165 insertions(+), 28 deletions(-) create mode 100644 be/test/vec/aggregate_functions/agg_bitmap_test.cpp diff --git a/be/src/util/bitmap_value.h b/be/src/util/bitmap_value.h index 0664735599a8ac..71edf62a8adb11 100644 --- a/be/src/util/bitmap_value.h +++ b/be/src/util/bitmap_value.h @@ -1172,10 +1172,11 @@ class BitmapValue { using SetContainer = phmap::flat_hash_set; // Construct an empty bitmap. - BitmapValue() : _type(EMPTY), _is_shared(false) {} + BitmapValue() : _sv(0), _bitmap(nullptr), _type(EMPTY), _is_shared(false) { _set.clear(); } // Construct a bitmap with one element. - explicit BitmapValue(uint64_t value) : _sv(value), _type(SINGLE), _is_shared(false) {} + explicit BitmapValue(uint64_t value) + : _sv(value), _bitmap(nullptr), _type(SINGLE), _is_shared(false) {} // Construct a bitmap from serialized data. explicit BitmapValue(const char* src) : _is_shared(false) { @@ -1199,7 +1200,7 @@ class BitmapValue { break; } - if (other._type != EMPTY) { + if (other._type == BITMAP) { _is_shared = true; // should also set other's state to shared, so that other bitmap value will // create a new bitmap when it wants to modify it. @@ -1229,6 +1230,10 @@ class BitmapValue { } BitmapValue& operator=(const BitmapValue& other) { + if (this == &other) { + return *this; + } + reset(); _type = other._type; switch (other._type) { case EMPTY: @@ -1244,7 +1249,7 @@ class BitmapValue { break; } - if (other._type != EMPTY) { + if (other._type == BITMAP) { _is_shared = true; // should also set other's state to shared, so that other bitmap value will // create a new bitmap when it wants to modify it. @@ -1265,6 +1270,7 @@ class BitmapValue { if (this == &other) { return *this; } + reset(); _type = other._type; switch (other._type) { @@ -1721,8 +1727,7 @@ class BitmapValue { BitmapValue& operator&=(const BitmapValue& rhs) { switch (rhs._type) { case EMPTY: - _type = EMPTY; - _bitmap.reset(); + reset(); // empty & any = empty break; case SINGLE: switch (_type) { @@ -1741,6 +1746,7 @@ class BitmapValue { _sv = rhs._sv; } _bitmap.reset(); + _is_shared = false; break; case SET: if (!_set.contains(rhs._sv)) { @@ -1797,6 +1803,7 @@ class BitmapValue { } _type = SET; _bitmap.reset(); + _is_shared = false; _convert_to_smaller_type(); break; case SET: @@ -1832,7 +1839,6 @@ class BitmapValue { case SINGLE: if (_sv == rhs._sv) { _type = EMPTY; - _bitmap.reset(); } else { add(rhs._sv); } @@ -2162,7 +2168,7 @@ class BitmapValue { // Return how many bytes are required to serialize this bitmap. // See BitmapTypeCode for the serialized format. - size_t getSizeInBytes() { + size_t getSizeInBytes() const { size_t res = 0; switch (_type) { case EMPTY: @@ -2613,12 +2619,13 @@ class BitmapValue { } } - void clear() { + void reset() { _type = EMPTY; - _bitmap.reset(); _sv = 0; + _set.clear(); + _is_shared = false; + _bitmap = nullptr; } - // Implement an iterator for convenience friend class BitmapValueIterator; typedef BitmapValueIterator b_iterator; diff --git a/be/src/vec/aggregate_functions/aggregate_function_bitmap.h b/be/src/vec/aggregate_functions/aggregate_function_bitmap.h index 418eef1b9b78d3..2d707dbebfd0e5 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_bitmap.h +++ b/be/src/vec/aggregate_functions/aggregate_function_bitmap.h @@ -143,7 +143,7 @@ struct AggregateFunctionBitmapData { void reset() { is_first = true; - value.clear(); + value.reset(); // it's better to call reset function by self firstly. } BitmapValue& get() { return value; } diff --git a/be/src/vec/aggregate_functions/aggregate_function_bitmap_agg.h b/be/src/vec/aggregate_functions/aggregate_function_bitmap_agg.h index 382957302ec245..a4c08aefe2ad43 100644 --- a/be/src/vec/aggregate_functions/aggregate_function_bitmap_agg.h +++ b/be/src/vec/aggregate_functions/aggregate_function_bitmap_agg.h @@ -46,7 +46,7 @@ struct AggregateFunctionBitmapAggData { void add(const T& value_) { value.add(value_); } - void reset() { value.clear(); } + void reset() { value.reset(); } void merge(const AggregateFunctionBitmapAggData& other) { value |= other.value; } diff --git a/be/src/vec/data_types/data_type_bitmap.cpp b/be/src/vec/data_types/data_type_bitmap.cpp index ccb39b080a33ce..79800029eb83ca 100644 --- a/be/src/vec/data_types/data_type_bitmap.cpp +++ b/be/src/vec/data_types/data_type_bitmap.cpp @@ -114,9 +114,7 @@ void DataTypeBitMap::to_string(const IColumn& column, size_t row_num, BufferWrit ColumnPtr ptr = result.first; row_num = result.second; - auto& data = - const_cast(assert_cast(*ptr).get_element(row_num)); - + const auto& data = assert_cast(*ptr).get_element(row_num); std::string buffer(data.getSizeInBytes(), '0'); data.write_to(const_cast(buffer.data())); ostr.write(buffer.c_str(), buffer.size()); diff --git a/be/src/vec/data_types/data_type_bitmap.h b/be/src/vec/data_types/data_type_bitmap.h index 12618c04ea890c..93fe7391a98b96 100644 --- a/be/src/vec/data_types/data_type_bitmap.h +++ b/be/src/vec/data_types/data_type_bitmap.h @@ -30,6 +30,7 @@ #include "serde/data_type_bitmap_serde.h" #include "util/bitmap_value.h" #include "vec/columns/column_complex.h" +#include "vec/columns/column_const.h" #include "vec/core/field.h" #include "vec/core/types.h" #include "vec/data_types/data_type.h" @@ -94,7 +95,12 @@ class DataTypeBitMap : public IDataType { bool can_be_inside_low_cardinality() const override { return false; } std::string to_string(const IColumn& column, size_t row_num) const override { - return "BitMap()"; + auto result = check_column_const_set_readability(column, row_num); + ColumnPtr ptr = result.first; + row_num = result.second; + + const auto& data = assert_cast(*ptr).get_element(row_num); + return data.to_string(); } void to_string(const IColumn& column, size_t row_num, BufferWritable& ostr) const override; Status from_string(ReadBuffer& rb, IColumn* column) const override; diff --git a/be/src/vec/functions/function_bitmap.cpp b/be/src/vec/functions/function_bitmap.cpp index 2083ec8420b138..cc97fb01d8e5c4 100644 --- a/be/src/vec/functions/function_bitmap.cpp +++ b/be/src/vec/functions/function_bitmap.cpp @@ -578,7 +578,7 @@ struct BitmapAndNot { mid_data &= rvec[i]; res[i] = lvec[i]; res[i] -= mid_data; - mid_data.clear(); + mid_data.reset(); } } static void vector_scalar(const TData& lvec, const BitmapValue& rval, TData& res) { @@ -589,7 +589,7 @@ struct BitmapAndNot { mid_data &= rval; res[i] = lvec[i]; res[i] -= mid_data; - mid_data.clear(); + mid_data.reset(); } } static void scalar_vector(const BitmapValue& lval, const TData& rvec, TData& res) { @@ -600,7 +600,7 @@ struct BitmapAndNot { mid_data &= rvec[i]; res[i] = lval; res[i] -= mid_data; - mid_data.clear(); + mid_data.reset(); } } }; @@ -624,7 +624,7 @@ struct BitmapAndNotCount { mid_data = lvec[i]; mid_data &= rvec[i]; res[i] = lvec[i].andnot_cardinality(mid_data); - mid_data.clear(); + mid_data.reset(); } } static void scalar_vector(const BitmapValue& lval, const TData& rvec, ResTData* res) { @@ -634,7 +634,7 @@ struct BitmapAndNotCount { mid_data = lval; mid_data &= rvec[i]; res[i] = lval.andnot_cardinality(mid_data); - mid_data.clear(); + mid_data.reset(); } } static void vector_scalar(const TData& lvec, const BitmapValue& rval, ResTData* res) { @@ -644,7 +644,7 @@ struct BitmapAndNotCount { mid_data = lvec[i]; mid_data &= rval; res[i] = lvec[i].andnot_cardinality(mid_data); - mid_data.clear(); + mid_data.reset(); } } }; diff --git a/be/test/util/bitmap_value_test.cpp b/be/test/util/bitmap_value_test.cpp index 6271300ecbb0da..e7652199ab03f9 100644 --- a/be/test/util/bitmap_value_test.cpp +++ b/be/test/util/bitmap_value_test.cpp @@ -24,6 +24,7 @@ #include #include +#include "gtest/gtest.h" #include "gtest/gtest_pred_impl.h" #include "util/coding.h" @@ -422,7 +423,7 @@ TEST(BitmapValueTest, set) { bitmap_value.add(4294967297); EXPECT_EQ(bitmap_value.get_type_code(), BitmapTypeCode::SINGLE64); - bitmap_value.clear(); + bitmap_value.reset(); bitmap_value.add(10); EXPECT_EQ(bitmap_value.get_type_code(), BitmapTypeCode::SINGLE32); @@ -494,7 +495,7 @@ TEST(BitmapValueTest, add) { bitmap_value.add_many(values.data(), values.size()); EXPECT_EQ(bitmap_value.get_type_code(), BitmapTypeCode::BITMAP32); - bitmap_value.clear(); + bitmap_value.reset(); values.clear(); values.resize(31); std::iota(values.begin(), values.end(), 0); @@ -545,6 +546,39 @@ void check_bitmap_value_operator(const BitmapValue& left, const BitmapValue& rig EXPECT_EQ(copy.cardinality(), left_cardinality + right_cardinality - and_cardinality * 2); } +// '=' +TEST(BitmapValueTest, copy_operator) { + BitmapValue test_bitmap; + + std::vector values1(31); + BitmapValue bitmap; + values1.resize(128); + std::iota(values1.begin(), values1.begin() + 16, 0); + std::iota(values1.begin() + 16, values1.begin() + 32, 4294967297); + std::iota(values1.begin() + 32, values1.begin() + 64, 8589934594); + std::iota(values1.begin() + 64, values1.end(), 42949672970); + bitmap.add_many(values1.data(), values1.size()); + + test_bitmap = bitmap; //should be bitmap + EXPECT_EQ(test_bitmap.cardinality(), bitmap.cardinality()); + EXPECT_EQ(test_bitmap.to_string(), bitmap.to_string()); + + BitmapValue single(1); + test_bitmap = single; //should be single + EXPECT_EQ(test_bitmap.cardinality(), 1); + EXPECT_EQ(test_bitmap.cardinality(), single.cardinality()); + EXPECT_EQ(test_bitmap.to_string(), single.to_string()); + + BitmapValue empty; + test_bitmap = empty; // should be empty + EXPECT_TRUE(test_bitmap.empty()); + + BitmapValue bitmap2(bitmap); + EXPECT_EQ(bitmap2.to_string(), bitmap.to_string()); + bitmap2 = bitmap; + EXPECT_EQ(bitmap2.to_string(), bitmap.to_string()); +} + // '-=', '|=', '&=', '^=' TEST(BitmapValueTest, operators) { config::enable_set_in_bitmap_value = true; @@ -658,7 +692,7 @@ TEST(BitmapValueTest, write_read) { buffer.reset(new char[size]); bitmap_single.write_to(buffer.get()); - deserialized.clear(); + deserialized.reset(); deserialized.deserialize(buffer.get()); check_bitmap_equal(deserialized, bitmap_single); @@ -667,7 +701,7 @@ TEST(BitmapValueTest, write_read) { buffer.reset(new char[size]); bitmap_set.write_to(buffer.get()); - deserialized.clear(); + deserialized.reset(); deserialized.deserialize(buffer.get()); check_bitmap_equal(deserialized, bitmap_set); @@ -676,7 +710,7 @@ TEST(BitmapValueTest, write_read) { buffer.reset(new char[size]); bitmap.write_to(buffer.get()); - deserialized.clear(); + deserialized.reset(); deserialized.deserialize(buffer.get()); check_bitmap_equal(deserialized, bitmap); diff --git a/be/test/vec/aggregate_functions/agg_bitmap_test.cpp b/be/test/vec/aggregate_functions/agg_bitmap_test.cpp new file mode 100644 index 00000000000000..6ca85efe3210cb --- /dev/null +++ b/be/test/vec/aggregate_functions/agg_bitmap_test.cpp @@ -0,0 +1,92 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "gtest/gtest_pred_impl.h" +#include "util/bitmap_value.h" +#include "vec/aggregate_functions/aggregate_function.h" +#include "vec/aggregate_functions/aggregate_function_simple_factory.h" +#include "vec/columns/column.h" +#include "vec/columns/column_complex.h" +#include "vec/columns/column_string.h" +#include "vec/columns/column_vector.h" +#include "vec/columns/columns_number.h" +#include "vec/common/string_ref.h" +#include "vec/core/field.h" +#include "vec/core/types.h" +#include "vec/data_types/data_type_bitmap.h" +#include "vec/data_types/data_type_decimal.h" +#include "vec/data_types/data_type_number.h" +#include "vec/data_types/data_type_string.h" + +const int agg_test_batch_size = 10; + +namespace doris::vectorized { +// declare function +void register_aggregate_function_bitmap(AggregateFunctionSimpleFactory& factory); + +TEST(AggBitmapTest, bitmap_union_test) { + std::string function_name = "bitmap_union"; + auto data_type = std::make_shared(); + // Prepare test data. + auto column_bitmap = data_type->create_column(); + for (int i = 0; i < agg_test_batch_size; i++) { + BitmapValue bitmap_value(i); + assert_cast(*column_bitmap).insert_value(bitmap_value); + } + + // Prepare test function and parameters. + AggregateFunctionSimpleFactory factory; + register_aggregate_function_bitmap(factory); + DataTypes data_types = {data_type}; + auto agg_function = factory.get(function_name, data_types); + agg_function->set_version(3); + std::unique_ptr memory(new char[agg_function->size_of_data()]); + AggregateDataPtr place = memory.get(); + agg_function->create(place); + + // Do aggregation. + const IColumn* column[1] = {column_bitmap.get()}; + for (int i = 0; i < agg_test_batch_size; i++) { + agg_function->add(place, column, i, nullptr); + } + + // Check result. + ColumnBitmap ans; + agg_function->insert_result_into(place, ans); + EXPECT_EQ(ans.size(), 1); + EXPECT_EQ(ans.get_element(0).cardinality(), agg_test_batch_size); + agg_function->destroy(place); + + auto dst = agg_function->create_serialize_column(); + agg_function->streaming_agg_serialize_to_column(column, dst, agg_test_batch_size, nullptr); + + for (size_t i = 0; i != agg_test_batch_size; ++i) { + EXPECT_EQ(std::to_string(i), assert_cast(*dst).get_element(i).to_string()); + } +} + +} // namespace doris::vectorized From 95f74f1544d9ee5173117194af1a599ef2175303 Mon Sep 17 00:00:00 2001 From: amory Date: Thu, 9 Nov 2023 10:56:14 +0800 Subject: [PATCH 74/88] [FIX](complextype)fix shrink in topN for complex type #26609 --- be/src/exec/rowid_fetcher.cpp | 33 ++++++++++++------- ...nestedtypes_csv_insert_into_with_s3.groovy | 1 + ...estedtypes_json_insert_into_with_s3.groovy | 1 + 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/be/src/exec/rowid_fetcher.cpp b/be/src/exec/rowid_fetcher.cpp index 94fcd814bea6de..c7519c5b05ad14 100644 --- a/be/src/exec/rowid_fetcher.cpp +++ b/be/src/exec/rowid_fetcher.cpp @@ -193,6 +193,24 @@ Status RowIDFetcher::_merge_rpc_results(const PMultiGetRequest& request, return Status::OK(); } +bool _has_char_type(const TypeDescriptor& desc) { + switch (desc.type) { + case TYPE_CHAR: + return true; + case TYPE_ARRAY: + case TYPE_MAP: + case TYPE_STRUCT: + for (int idx = 0; idx < desc.children.size(); ++idx) { + if (_has_char_type(desc.children[idx])) { + return true; + } + } + return false; + default: + return false; + } +} + Status RowIDFetcher::fetch(const vectorized::ColumnPtr& column_row_ids, vectorized::Block* res_block) { CHECK(!_stubs.empty()); @@ -238,17 +256,10 @@ Status RowIDFetcher::fetch(const vectorized::ColumnPtr& column_row_ids, std::vector char_type_idx; for (size_t i = 0; i < _fetch_option.desc->slots().size(); i++) { const auto& column_desc = _fetch_option.desc->slots()[i]; - const TypeDescriptor* type_desc = &column_desc->type(); - do { - if (type_desc->type == TYPE_CHAR) { - char_type_idx.emplace_back(i); - break; - } else if (type_desc->type != TYPE_ARRAY) { - break; - } - // for Array or Array> - type_desc = &type_desc->children[0]; - } while (true); + const TypeDescriptor& type_desc = column_desc->type(); + if (_has_char_type(type_desc)) { + char_type_idx.push_back(i); + } } res_block->shrink_char_type_column_suffix_zero(char_type_idx); VLOG_DEBUG << "dump block:" << res_block->dump_data(0, 10); diff --git a/regression-test/suites/datatype_p0/nested_types/query/test_nestedtypes_csv_insert_into_with_s3.groovy b/regression-test/suites/datatype_p0/nested_types/query/test_nestedtypes_csv_insert_into_with_s3.groovy index e55c8e540def89..ab9dff9ffb2407 100644 --- a/regression-test/suites/datatype_p0/nested_types/query/test_nestedtypes_csv_insert_into_with_s3.groovy +++ b/regression-test/suites/datatype_p0/nested_types/query/test_nestedtypes_csv_insert_into_with_s3.groovy @@ -24,6 +24,7 @@ suite("test_nestedtypes_csv_insert_into_with_s3", "p0") { sql 'use regression_test_datatype_p0_nested_types' sql 'set enable_nereids_planner=false' sql 'set max_allowed_packet=4194304' + sql 'set topn_opt_limit_threshold=10000' sql """ADMIN SET FRONTEND CONFIG ('disable_nested_complex_type' = 'false')""" String ak = getS3AK() diff --git a/regression-test/suites/datatype_p0/nested_types/query/test_nestedtypes_json_insert_into_with_s3.groovy b/regression-test/suites/datatype_p0/nested_types/query/test_nestedtypes_json_insert_into_with_s3.groovy index 68fd6b1f6f1391..35d154cbbd059e 100644 --- a/regression-test/suites/datatype_p0/nested_types/query/test_nestedtypes_json_insert_into_with_s3.groovy +++ b/regression-test/suites/datatype_p0/nested_types/query/test_nestedtypes_json_insert_into_with_s3.groovy @@ -24,6 +24,7 @@ suite("test_nestedtypes_json_insert_into_with_s3", "p0") { sql 'use regression_test_datatype_p0_nested_types' sql 'set enable_nereids_planner=false' sql 'set max_allowed_packet=4194304' + sql 'set topn_opt_limit_threshold=10000' sql """ADMIN SET FRONTEND CONFIG ('disable_nested_complex_type' = 'false')""" String ak = getS3AK() From 01094fd25ed539a8025066d8823c1e907109048a Mon Sep 17 00:00:00 2001 From: zclllyybb Date: Thu, 9 Nov 2023 11:00:15 +0800 Subject: [PATCH 75/88] [Coverage](BE) Delete vinfo_func in BE (#26562) Delete vinfo_func in BE --- be/src/vec/exprs/vexpr.cpp | 5 --- be/src/vec/exprs/vinfo_func.cpp | 71 --------------------------------- be/src/vec/exprs/vinfo_func.h | 50 ----------------------- 3 files changed, 126 deletions(-) delete mode 100644 be/src/vec/exprs/vinfo_func.cpp delete mode 100644 be/src/vec/exprs/vinfo_func.h diff --git a/be/src/vec/exprs/vexpr.cpp b/be/src/vec/exprs/vexpr.cpp index bcd06cb6640268..b06579f7957d25 100644 --- a/be/src/vec/exprs/vexpr.cpp +++ b/be/src/vec/exprs/vexpr.cpp @@ -41,7 +41,6 @@ #include "vec/exprs/vectorized_fn_call.h" #include "vec/exprs/vexpr_context.h" #include "vec/exprs/vin_predicate.h" -#include "vec/exprs/vinfo_func.h" #include "vec/exprs/vlambda_function_call_expr.h" #include "vec/exprs/vlambda_function_expr.h" #include "vec/exprs/vliteral.h" @@ -303,10 +302,6 @@ Status VExpr::create_expr(const TExprNode& expr_node, VExprSPtr& expr) { expr = VCaseExpr::create_shared(expr_node); break; } - case TExprNodeType::INFO_FUNC: { - expr = VInfoFunc::create_shared(expr_node); - break; - } case TExprNodeType::TUPLE_IS_NULL_PRED: { expr = VTupleIsNullPredicate::create_shared(expr_node); break; diff --git a/be/src/vec/exprs/vinfo_func.cpp b/be/src/vec/exprs/vinfo_func.cpp deleted file mode 100644 index c262882b317e90..00000000000000 --- a/be/src/vec/exprs/vinfo_func.cpp +++ /dev/null @@ -1,71 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#include "vec/exprs/vinfo_func.h" - -#include -#include -#include - -#include -#include -#include - -#include "runtime/define_primitive_type.h" -#include "runtime/types.h" -#include "vec/core/block.h" -#include "vec/core/field.h" -#include "vec/core/types.h" -#include "vec/data_types/data_type.h" - -namespace doris { -namespace vectorized { -class VExprContext; -} // namespace vectorized -} // namespace doris - -namespace doris::vectorized { - -VInfoFunc::VInfoFunc(const TExprNode& node) : VExpr(node) { - Field field; - switch (_type.type) { - case TYPE_BIGINT: { - field = Int64(node.info_func.int_value); - break; - } - case TYPE_STRING: - case TYPE_CHAR: - case TYPE_VARCHAR: { - field = node.info_func.str_value; - break; - } - default: { - DCHECK(false) << "Invalid type: " << _type.type; - break; - } - } - this->_column_ptr = _data_type->create_column_const(1, field); -} - -Status VInfoFunc::execute(VExprContext* context, vectorized::Block* block, int* result_column_id) { - // Info function should return least one row, e.g. select current_user(). - size_t row_size = std::max(block->rows(), size_t(1)); - *result_column_id = VExpr::insert_param(block, {_column_ptr, _data_type, _expr_name}, row_size); - return Status::OK(); -} - -} // namespace doris::vectorized diff --git a/be/src/vec/exprs/vinfo_func.h b/be/src/vec/exprs/vinfo_func.h deleted file mode 100644 index c21ef6bf07f89d..00000000000000 --- a/be/src/vec/exprs/vinfo_func.h +++ /dev/null @@ -1,50 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. - -#pragma once - -#include - -#include "common/object_pool.h" -#include "common/status.h" -#include "vec/data_types/data_type.h" -#include "vec/exprs/vexpr.h" - -namespace doris { -class TExprNode; - -namespace vectorized { -class Block; -class VExprContext; - -class VInfoFunc : public VExpr { - ENABLE_FACTORY_CREATOR(VInfoFunc); - -public: - VInfoFunc(const TExprNode& node); - ~VInfoFunc() override = default; - - const std::string& expr_name() const override { return _expr_name; } - Status execute(VExprContext* context, Block* block, int* result_column_id) override; - -private: - const std::string _expr_name = "vinfofunc expr"; - ColumnPtr _column_ptr; -}; -} // namespace vectorized - -} // namespace doris From f6b7046a6e0aea13ad5cf13932b396b518fd7e98 Mon Sep 17 00:00:00 2001 From: Tiewei Fang <43782773+BePPPower@users.noreply.github.com> Date: Thu, 9 Nov 2023 11:59:35 +0800 Subject: [PATCH 76/88] [fix](regression-test) add tests for jdbc catalog (#26608) --- .../oracle/init/03-create-table.sql | 37 +++++++++++ .../docker-compose/oracle/init/04-insert.sql | 15 +++++ .../postgresql/init/02-create-table.sql | 28 ++++++++ .../postgresql/init/04-insert.sql | 7 ++ docs/en/docs/lakehouse/multi-catalog/jdbc.md | 1 + .../docs/lakehouse/multi-catalog/jdbc.md | 1 + .../jdbc/test_mysql_jdbc_catalog.out | 46 +++++++++++++ .../jdbc/test_oracle_jdbc_catalog.out | 47 ++++++++++++++ .../jdbc/test_pg_jdbc_catalog.out | 39 +++++++++++ .../jdbc/test_mysql_jdbc_catalog.groovy | 57 +++++++++++++++++ .../jdbc/test_oracle_jdbc_catalog.groovy | 64 +++++++++++++++++++ .../jdbc/test_pg_jdbc_catalog.groovy | 54 ++++++++++++++++ 12 files changed, 396 insertions(+) diff --git a/docker/thirdparties/docker-compose/oracle/init/03-create-table.sql b/docker/thirdparties/docker-compose/oracle/init/03-create-table.sql index 829e2925a637e1..046f18c0dc65fc 100644 --- a/docker/thirdparties/docker-compose/oracle/init/03-create-table.sql +++ b/docker/thirdparties/docker-compose/oracle/init/03-create-table.sql @@ -131,3 +131,40 @@ name varchar2(20), age number(2), score number(3,1) ); + + +create table doris_test.test_all_types ( + id int, + n1 number, + n2 number(38), + n3 number(9,2), + n4 int, + n5 smallint, + n6 decimal(5,2), + n7 float, + n8 float(2), + n9 real, + tinyint_value1 number(2,0), + smallint_value1 number(4,0), + int_value1 number(9,0), + bigint_value1 number(18,0), + tinyint_value2 number(3,0), + smallint_value2 number(5,0), + int_value2 number(10,0), + bigint_value2 number(19,0), + country char, + city nchar(6), + address varchar2(4000), + name nvarchar2(6), + remark long, + num1 NUMBER(5,2), + num2 NUMBER(5, -2), + num4 NUMBER(5,7), + t1 date, + t2 timestamp(3), + t3 timestamp(6), + t4 timestamp(9), + t5 timestamp, + t6 interval year(3) to month, + t7 interval day(3) to second(6) +); diff --git a/docker/thirdparties/docker-compose/oracle/init/04-insert.sql b/docker/thirdparties/docker-compose/oracle/init/04-insert.sql index 17f68f994a237a..888cdf5bf7e4e4 100644 --- a/docker/thirdparties/docker-compose/oracle/init/04-insert.sql +++ b/docker/thirdparties/docker-compose/oracle/init/04-insert.sql @@ -86,4 +86,19 @@ insert into doris_test."student2" values (2, 'bob', 21, 90.5); insert into doris_test."student2" values (3, 'jerry', 23, 88.0); insert into doris_test."student2" values (4, 'andy', 21, 93); +insert into doris_test.test_all_types values +(1, 111, 123, 7456123.89, 573, 34, 673.43, 34.1264, 56.2, 23.231, +99, 9999, 999999999, 999999999999999999, 999, 99999, 9999999999, 9999999999999999999, +'1', 'china', 'beijing', 'alice', 'abcdefghrjkmnopq', +123.45, 12345, 0.0012345, +to_date('2022-1-21 5:23:01','yyyy-mm-dd hh24:mi:ss'), to_timestamp('20191112203357.999', 'yyyymmddhh24miss.ff'), to_timestamp('20191112203357.999997623', 'yyyymmddhh24miss.ff'), to_timestamp_tz('20191112203357.999996623', 'yyyymmddhh24miss.ff'), to_timestamp_tz('20191112203357.999996623', 'yyyymmddhh24miss.ff'), interval '223-9' year(3) to month, interval '12 10:23:01.1234568' day to second +); +insert into doris_test.test_all_types values +(2, null, null, null, null, null, null, null, null, null, +null, null, null, null, null, null, null, null, +null, null, null, null, null, +null, null, null, +null, null, null, null, null, null, null +); + commit; diff --git a/docker/thirdparties/docker-compose/postgresql/init/02-create-table.sql b/docker/thirdparties/docker-compose/postgresql/init/02-create-table.sql index 92952cdd229141..a026e560d05253 100644 --- a/docker/thirdparties/docker-compose/postgresql/init/02-create-table.sql +++ b/docker/thirdparties/docker-compose/postgresql/init/02-create-table.sql @@ -151,6 +151,34 @@ CREATE TABLE catalog_pg_test.test12 ( uuid_value uuid ); +CREATE TABLE catalog_pg_test.test_all_types ( + ID INT NOT NULL, + char_value char(100), + varchar_value varchar(128), + date_value date, + smallint_value smallint, + int_value int, + bigint_value bigint, + timestamp_value timestamp, + decimal_value decimal(10, 3), + bit_value bit, + real_value real, + cidr_value cidr, + inet_value inet, + macaddr_value macaddr, + bitn_value bit(10), + bitnv_value bit varying(10), + serial4_value serial4, + jsonb_value jsonb, + point_value point, + line_value line, + lseg_value lseg, + box_value box, + path_value path, + polygon_value polygon, + circle_value circle +); + CREATE TABLE catalog_pg_test.test_insert ( id varchar(128), name varchar(128), diff --git a/docker/thirdparties/docker-compose/postgresql/init/04-insert.sql b/docker/thirdparties/docker-compose/postgresql/init/04-insert.sql index 245e70b2b2f6d1..2ea1e15b8be7f7 100644 --- a/docker/thirdparties/docker-compose/postgresql/init/04-insert.sql +++ b/docker/thirdparties/docker-compose/postgresql/init/04-insert.sql @@ -2656,6 +2656,13 @@ insert into catalog_pg_test.test12 values insert into catalog_pg_test.test12 values (2, '980dd890-f7fe-4fff-999d-873516108b2e'); +insert into catalog_pg_test.test_all_types values +(1, 'abc', 'def', '2022-10-11', 1, 2, 3, '2022-10-22 10:59:59', 34.123, cast(0 as bit), 12.123456, '10.16.10.14','10.16.10.14','ff:ff:ff:ff:ff:AA', +'1010101010', cast(10 as bit(5)), 1, '{"id":1}', '(1,1)', '{1,1,1}', '(1,1),(2,2)', '(1,1),(2,2)', '(1,1),(2,2),(2,1)', +'((1,1),(2,2),(2,1))', '<(0,0),1>'), +(2, null, null, null, null, null, null, null, null, null, null, null, null, null, +null, null, 2, null, null, null, null, null, null, null, null); + INSERT INTO catalog_pg_test.wkb_test (location) SELECT ST_AsBinary(ST_GeomFromText('POLYGON((0 0,0 1,1 1,1 0,0 0))',4326)); INSERT INTO catalog_pg_test.dt_test (ts_field, tzt_field) diff --git a/docs/en/docs/lakehouse/multi-catalog/jdbc.md b/docs/en/docs/lakehouse/multi-catalog/jdbc.md index db41b033a49aac..13151bc2f8db5b 100644 --- a/docs/en/docs/lakehouse/multi-catalog/jdbc.md +++ b/docs/en/docs/lakehouse/multi-catalog/jdbc.md @@ -205,6 +205,7 @@ CREATE CATALOG jdbc_mysql PROPERTIES ( | FLOAT | FLOAT | | | DOUBLE | DOUBLE | | | DECIMAL | DECIMAL | | +| UNSIGNED DECIMAL(p,s) | DECIMAL(p+1,s) / STRING | If p+1>38, the Doris STRING type will be used. | | DATE | DATE | | | TIMESTAMP | DATETIME | | | DATETIME | DATETIME | | diff --git a/docs/zh-CN/docs/lakehouse/multi-catalog/jdbc.md b/docs/zh-CN/docs/lakehouse/multi-catalog/jdbc.md index 2896b5c410a180..545f5ada6e23e6 100644 --- a/docs/zh-CN/docs/lakehouse/multi-catalog/jdbc.md +++ b/docs/zh-CN/docs/lakehouse/multi-catalog/jdbc.md @@ -205,6 +205,7 @@ CREATE CATALOG jdbc_mysql PROPERTIES ( | FLOAT | FLOAT | | | DOUBLE | DOUBLE | | | DECIMAL | DECIMAL | | +| UNSIGNED DECIMAL(p,s) | DECIMAL(p+1,s) / STRING | 如果p+1>38, 将使用Doris STRING类型 | | DATE | DATE | | | TIMESTAMP | DATETIME | | | DATETIME | DATETIME | | diff --git a/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out b/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out index 8fef1684317884..38bb7a67828b00 100644 --- a/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out +++ b/regression-test/data/external_table_p0/jdbc/test_mysql_jdbc_catalog.out @@ -283,6 +283,52 @@ sys 202 302 402 502 602 4.14159 5.1415926 6.14159 0 -124 -302 2013 -402 -502 -602 2012-11-01 2012-10-26T02:08:39.345700 2013-10-26T08:09:18 -5.14145 -6.1400000001 -7.1400 row2 line2 09:11:09.567 text2 0xE86F6C6C6F20576F726C67 {"age":18,"city":"ChongQing","name":"Gaoxin"} Option1,Option2 0x2F 0x58676C6C6F00000000000000 0x88656C6C9F Value3 203 303 403 503 603 7.14159 8.1415926 9.14159 0 \N -402 2017 -602 -902 -1102 2012-11-02 \N 2013-10-27T08:11:18 -5.14145 -6.1400000000001 -7.1400 row3 line3 09:11:09.567 text3 0xE86F6C6C6F20576F726C67 {"age":24,"city":"ChongQing","name":"ChenQi"} Option2 0x2F 0x58676C6C6F00000000000000 \N Value1 +-- !select_insert_all_types -- +\N 302 \N 502 602 4.14159 \N 6.14159 \N -124 -302 2013 -402 -502 -602 \N 2012-10-26T02:08:39.345700 2013-10-26T08:09:18 -5.14145 \N -7.1400 row2 \N 09:11:09.567 text2 0xE86F6C6C6F20576F726C67 \N \N 0x2F \N 0x88656C6C9F Value3 +201 301 401 501 601 3.14159 4.1415926 5.14159 1 -123 -301 2012 -401 -501 -601 2012-10-30 2012-10-25T12:05:36.345700 2012-10-25T08:08:08 -4.14145 -5.1400000001 -6.1400 row1 line1 09:09:09.567 text1 0x48656C6C6F20576F726C64 {"age":30,"city":"London","name":"Alice"} Option1,Option3 0x2A 0x48656C6C6F00000000000000 0x48656C6C6F Value2 +202 302 402 502 602 4.14159 5.1415926 6.14159 0 -124 -302 2013 -402 -502 -602 2012-11-01 2012-10-26T02:08:39.345700 2013-10-26T08:09:18 -5.14145 -6.1400000001 -7.1400 row2 line2 09:11:09.567 text2 0xE86F6C6C6F20576F726C67 {"age":18,"city":"ChongQing","name":"Gaoxin"} Option1,Option2 0x2F 0x58676C6C6F00000000000000 0x88656C6C9F Value3 +203 303 403 503 603 7.14159 8.1415926 9.14159 0 \N -402 2017 -602 -902 -1102 2012-11-02 \N 2013-10-27T08:11:18 -5.14145 -6.1400000000001 -7.1400 row3 line3 09:11:09.567 text3 0xE86F6C6C6F20576F726C67 {"age":24,"city":"ChongQing","name":"ChenQi"} Option2 0x2F 0x58676C6C6F00000000000000 \N Value1 + +-- !ctas -- +\N 302 \N 502 602 4.14159 \N 6.14159 \N -124 -302 2013 -402 -502 -602 \N 2012-10-26T02:08:39.345700 2013-10-26T08:09:18 -5.14145 \N -7.1400 row2 \N 09:11:09.567 text2 0xE86F6C6C6F20576F726C67 \N \N 0x2F \N 0x88656C6C9F Value3 +201 301 401 501 601 3.14159 4.1415926 5.14159 1 -123 -301 2012 -401 -501 -601 2012-10-30 2012-10-25T12:05:36.345700 2012-10-25T08:08:08 -4.14145 -5.1400000001 -6.1400 row1 line1 09:09:09.567 text1 0x48656C6C6F20576F726C64 {"age":30,"city":"London","name":"Alice"} Option1,Option3 0x2A 0x48656C6C6F00000000000000 0x48656C6C6F Value2 +202 302 402 502 602 4.14159 5.1415926 6.14159 0 -124 -302 2013 -402 -502 -602 2012-11-01 2012-10-26T02:08:39.345700 2013-10-26T08:09:18 -5.14145 -6.1400000001 -7.1400 row2 line2 09:11:09.567 text2 0xE86F6C6C6F20576F726C67 {"age":18,"city":"ChongQing","name":"Gaoxin"} Option1,Option2 0x2F 0x58676C6C6F00000000000000 0x88656C6C9F Value3 +203 303 403 503 603 7.14159 8.1415926 9.14159 0 \N -402 2017 -602 -902 -1102 2012-11-02 \N 2013-10-27T08:11:18 -5.14145 -6.1400000000001 -7.1400 row3 line3 09:11:09.567 text3 0xE86F6C6C6F20576F726C67 {"age":24,"city":"ChongQing","name":"ChenQi"} Option2 0x2F 0x58676C6C6F00000000000000 \N Value1 + +-- !ctas_desc -- +bigint BIGINT Yes false \N NONE +bigint_u LARGEINT Yes false \N NONE +binary TEXT Yes false \N NONE +bit TEXT Yes false \N NONE +blob TEXT Yes false \N NONE +boolean TINYINT Yes false \N NONE +char VARCHAR(*) Yes false \N NONE +date DATE Yes false \N NONE +datetime DATETIME Yes false \N NONE +decimal DECIMAL(12, 4) Yes false \N NONE +decimal_u DECIMAL(19, 5) Yes false \N NONE +double DOUBLE Yes false \N NONE +double_u DOUBLE Yes false \N NONE +enum TEXT Yes false \N NONE +float FLOAT Yes false \N NONE +float_u FLOAT Yes false \N NONE +int INT Yes false \N NONE +int_u BIGINT Yes false \N NONE +json JSON Yes false \N NONE +mediumint INT Yes false \N NONE +mediumint_u INT Yes true \N +set TEXT Yes false \N NONE +smallint SMALLINT Yes false \N NONE +smallint_u INT Yes true \N +text TEXT Yes false \N NONE +time TEXT Yes false \N NONE +timestamp DATETIME(4) Yes false \N NONE +tinyint TINYINT Yes false \N NONE +tinyint_u SMALLINT Yes true \N +varbinary TEXT Yes false \N NONE +varchar VARCHAR(10) Yes false \N NONE +year SMALLINT Yes false \N NONE + -- !mysql_view -- 10086 4294967295 201 diff --git a/regression-test/data/external_table_p0/jdbc/test_oracle_jdbc_catalog.out b/regression-test/data/external_table_p0/jdbc/test_oracle_jdbc_catalog.out index 1be0feb1a90a66..519c7ab131cd98 100644 --- a/regression-test/data/external_table_p0/jdbc/test_oracle_jdbc_catalog.out +++ b/regression-test/data/external_table_p0/jdbc/test_oracle_jdbc_catalog.out @@ -115,6 +115,53 @@ doris2 19 doris3 20 doris3 20 +-- !select_all_types -- +1 111 123 7456123.89 573 34 673.43 34.1264 60.0 23.231 99 9999 999999999 999999999999999999 999 99999 9999999999 9999999999999999999 1 china beijing alice abcdefghrjkmnopq 123.45 12300 0.0012345 2022-01-21T05:23:01 2019-11-12T20:33:57.999 2019-11-12T20:33:57.999998 2019-11-12T20:33:57.999996 2019-11-12T20:33:57.999997 223-9 12 10:23:1.123457 +2 \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N + +-- !ctas -- +1 111 123 7456123.89 573 34 673.43 34.1264 60.0 23.231 99 9999 999999999 999999999999999999 999 99999 9999999999 9999999999999999999 1 china beijing alice abcdefghrjkmnopq 123.45 12300 0.0012345 2022-01-21T05:23:01 2019-11-12T20:33:57.999 2019-11-12T20:33:57.999998 2019-11-12T20:33:57.999996 2019-11-12T20:33:57.999997 223-9 12 10:23:1.123457 +2 \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N + +-- !ctas_desc -- +ADDRESS TEXT Yes false \N NONE +BIGINT_VALUE1 BIGINT Yes false \N NONE +BIGINT_VALUE2 LARGEINT Yes false \N NONE +CITY TEXT Yes false \N NONE +COUNTRY TEXT Yes false \N NONE +ID LARGEINT Yes true \N +INT_VALUE1 INT Yes false \N NONE +INT_VALUE2 BIGINT Yes false \N NONE +N1 TEXT Yes false \N NONE +N2 LARGEINT Yes false \N NONE +N3 DECIMAL Yes false \N NONE +N4 LARGEINT Yes false \N NONE +N5 LARGEINT Yes false \N NONE +N6 DECIMAL(5, 2) Yes false \N NONE +N7 DOUBLE Yes false \N NONE +N8 DOUBLE Yes false \N NONE +N9 DOUBLE Yes false \N NONE +NAME TEXT Yes false \N NONE +NUM1 DECIMAL(5, 2) Yes false \N NONE +NUM2 INT Yes false \N NONE +NUM4 DECIMAL(7, 7) Yes false \N NONE +REMARK TEXT Yes false \N NONE +SMALLINT_VALUE1 SMALLINT Yes false \N NONE +SMALLINT_VALUE2 INT Yes false \N NONE +T1 DATETIME Yes false \N NONE +T2 DATETIME(3) Yes false \N NONE +T3 DATETIME(6) Yes false \N NONE +T4 DATETIME(6) Yes false \N NONE +T5 DATETIME(6) Yes false \N NONE +T6 TEXT Yes false \N NONE +T7 TEXT Yes false \N NONE +TINYINT_VALUE1 TINYINT Yes false \N NONE +TINYINT_VALUE2 SMALLINT Yes false \N NONE + +-- !select_insert_all_types -- +1 111 123 7456123.89 573 34 673.43 34.1264 60.0 23.231 99 9999 999999999 999999999999999999 999 99999 9999999999 9999999999999999999 1 china beijing alice abcdefghrjkmnopq 123.45 12300 0.0012345 2022-01-21T05:23:01 2019-11-12T20:33:57.999 2019-11-12T20:33:57.999998 2019-11-12T20:33:57.999996 2019-11-12T20:33:57.999997 223-9 12 10:23:1.123457 +2 \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N + -- !specified_database -- DORIS_TEST diff --git a/regression-test/data/external_table_p0/jdbc/test_pg_jdbc_catalog.out b/regression-test/data/external_table_p0/jdbc/test_pg_jdbc_catalog.out index 1a2cf62abf0ed6..b2a944cde6a160 100644 --- a/regression-test/data/external_table_p0/jdbc/test_pg_jdbc_catalog.out +++ b/regression-test/data/external_table_p0/jdbc/test_pg_jdbc_catalog.out @@ -2214,6 +2214,45 @@ doris2 19 doris3 20 doris3 20 +-- !select_all_types -- +1 abc def 2022-10-11 1 2 3 2022-10-22T10:59:59 34.123 false 12.123456 10.16.10.14/32 10.16.10.14 ff:ff:ff:ff:ff:aa 1010101010 01010 1 {"id":1} (1.0,1.0) {1.0,1.0,1.0} [(1.0,1.0),(2.0,2.0)] (2.0,2.0),(1.0,1.0) ((1.0,1.0),(2.0,2.0),(2.0,1.0)) ((1.0,1.0),(2.0,2.0),(2.0,1.0)) <(0.0,0.0),1.0> +2 \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 2 \N \N \N \N \N \N \N \N + +-- !ctas -- +1 abc def 2022-10-11 1 2 3 2022-10-22T10:59:59 34.123 false 12.123456 10.16.10.14/32 10.16.10.14 ff:ff:ff:ff:ff:aa 1010101010 01010 1 {"id":1} (1.0,1.0) {1.0,1.0,1.0} [(1.0,1.0),(2.0,2.0)] (2.0,2.0),(1.0,1.0) ((1.0,1.0),(2.0,2.0),(2.0,1.0)) ((1.0,1.0),(2.0,2.0),(2.0,1.0)) <(0.0,0.0),1.0> +2 \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 2 \N \N \N \N \N \N \N \N + +-- !ctas_desc -- +bigint_value BIGINT Yes false \N NONE +bit_value BOOLEAN Yes false \N NONE +bitn_value TEXT Yes false \N NONE +bitnv_value TEXT Yes false \N NONE +box_value TEXT Yes false \N NONE +char_value VARCHAR(*) Yes true \N +cidr_value TEXT Yes false \N NONE +circle_value TEXT Yes false \N NONE +date_value DATE Yes false \N NONE +decimal_value DECIMAL(10, 3) Yes false \N NONE +id INT No true \N +inet_value TEXT Yes false \N NONE +int_value INT Yes false \N NONE +jsonb_value JSON Yes false \N NONE +line_value TEXT Yes false \N NONE +lseg_value TEXT Yes false \N NONE +macaddr_value TEXT Yes false \N NONE +path_value TEXT Yes false \N NONE +point_value TEXT Yes false \N NONE +polygon_value TEXT Yes false \N NONE +real_value FLOAT Yes false \N NONE +serial4_value INT No false \N NONE +smallint_value SMALLINT Yes false \N NONE +timestamp_value DATETIME(6) Yes false \N NONE +varchar_value TEXT Yes false \N NONE + +-- !select_insert_all_types -- +1 abc def 2022-10-11 1 2 3 2022-10-22T10:59:59 34.123 false 12.123456 10.16.10.14/32 10.16.10.14 ff:ff:ff:ff:ff:aa 1010101010 01010 1 {"id":1} (1.0,1.0) {1.0,1.0,1.0} [(1.0,1.0),(2.0,2.0)] (2.0,2.0),(1.0,1.0) ((1.0,1.0),(2.0,2.0),(2.0,1.0)) ((1.0,1.0),(2.0,2.0),(2.0,1.0)) <(0.0,0.0),1.0> +2 \N \N \N \N \N \N \N \N \N \N \N \N \N \N \N 2 \N \N \N \N \N \N \N \N + -- !specified_database_1 -- doris_test diff --git a/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_catalog.groovy b/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_catalog.groovy index 6c68260857d7c6..f70c44057bbb10 100644 --- a/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_catalog.groovy +++ b/regression-test/suites/external_table_p0/jdbc/test_mysql_jdbc_catalog.groovy @@ -56,6 +56,8 @@ suite("test_mysql_jdbc_catalog", "p0,external,mysql,external_docker,external_doc String ex_tb20 = "ex_tb20"; String test_insert = "test_insert"; String test_insert2 = "test_insert2"; + String test_insert_all_types = "test_insert_all_types"; + String test_ctas = "test_ctas"; String auto_default_t = "auto_default_t"; String dt = "dt"; String dt_null = "dt_null"; @@ -87,6 +89,46 @@ suite("test_mysql_jdbc_catalog", "p0,external,mysql,external_docker,external_doc PROPERTIES("replication_num" = "1"); """ + // used for testing all types + sql """ drop table if exists ${internal_db_name}.${test_insert_all_types} """ + sql """ + CREATE TABLE ${internal_db_name}.${test_insert_all_types} ( + `tinyint_u` SMALLINT, + `smallint_u` INT, + `mediumint_u` INT, + `int_u` BIGINT, + `bigint_u` LARGEINT, + `decimal_u` DECIMAL(18, 5), + `double_u` DOUBLE, + `float_u` FLOAT, + `boolean` TINYINT, + `tinyint` TINYINT, + `smallint` SMALLINT, + `year` SMALLINT, + `mediumint` INT, + `int` INT, + `bigint` BIGINT, + `date` DATE, + `timestamp` DATETIME(4) null, + `datetime` DATETIME, + `float` FLOAT, + `double` DOUBLE, + `decimal` DECIMAL(12, 4), + `char` CHAR(5), + `varchar` VARCHAR(10), + `time` STRING, + `text` STRING, + `blob` STRING, + `json` JSON, + `set` STRING, + `bit` STRING, + `binary` STRING, + `varbinary` STRING, + `enum` STRING + ) DISTRIBUTED BY HASH(tinyint_u) BUCKETS 10 + PROPERTIES("replication_num" = "1"); + """ + qt_sql """select current_catalog()""" sql """switch ${catalog_name}""" qt_sql """select current_catalog()""" @@ -248,6 +290,21 @@ suite("test_mysql_jdbc_catalog", "p0,external,mysql,external_docker,external_doc sql """use doris_test;""" qt_mysql_all_types """select * from all_types order by tinyint_u;""" + // test insert into internal.db.table select * from all_types + sql """ insert into internal.${internal_db_name}.${test_insert_all_types} select * from all_types; """ + order_qt_select_insert_all_types """ select * from internal.${internal_db_name}.${test_insert_all_types} order by tinyint_u; """ + + // test CTAS + sql """ drop table if exists internal.${internal_db_name}.${test_ctas} """ + sql """ create table internal.${internal_db_name}.${test_ctas} + PROPERTIES("replication_num" = "1") + AS select * from all_types; + """ + + order_qt_ctas """select * from internal.${internal_db_name}.${test_ctas} order by tinyint_u;""" + + order_qt_ctas_desc """desc internal.${internal_db_name}.${test_ctas};""" + sql """ drop catalog if exists ${catalog_name} """ // test mysql view diff --git a/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy b/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy index 77d3015239c27d..e762f2f4aaf41f 100644 --- a/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy +++ b/regression-test/suites/external_table_p0/jdbc/test_oracle_jdbc_catalog.groovy @@ -29,6 +29,9 @@ suite("test_oracle_jdbc_catalog", "p0,external,oracle,external_docker,external_d String oracle_port = context.config.otherConfigs.get("oracle_11_port"); String SID = "XE"; String test_insert = "TEST_INSERT"; + String test_all_types = "TEST_ALL_TYPES"; + String test_insert_all_types = "test_insert_all_types"; + String test_ctas = "test_ctas"; String inDorisTable = "doris_in_tb"; @@ -55,6 +58,49 @@ suite("test_oracle_jdbc_catalog", "p0,external,oracle,external_docker,external_d PROPERTIES("replication_num" = "1"); """ + sql """ drop table if exists ${internal_db_name}.${test_insert_all_types} """ + sql """ + CREATE TABLE ${internal_db_name}.${test_insert_all_types} ( + `ID` LARGEINT NULL, + `N1` TEXT NULL, + `N2` LARGEINT NULL, + `N3` DECIMAL(9, 2) NULL, + `N4` LARGEINT NULL, + `N5` LARGEINT NULL, + `N6` DECIMAL(5, 2) NULL, + `N7` DOUBLE NULL, + `N8` DOUBLE NULL, + `N9` DOUBLE NULL, + `TINYINT_VALUE1` TINYINT NULL, + `SMALLINT_VALUE1` SMALLINT NULL, + `INT_VALUE1` INT NULL, + `BIGINT_VALUE1` BIGINT NULL, + `TINYINT_VALUE2` SMALLINT NULL, + `SMALLINT_VALUE2` INT NULL, + `INT_VALUE2` BIGINT NULL, + `BIGINT_VALUE2` LARGEINT NULL, + `COUNTRY` TEXT NULL, + `CITY` TEXT NULL, + `ADDRESS` TEXT NULL, + `NAME` TEXT NULL, + `REMARK` TEXT NULL, + `NUM1` DECIMAL(5, 2) NULL, + `NUM2` INT NULL, + `NUM4` DECIMAL(7, 7) NULL, + `T1` DATETIME NULL, + `T2` DATETIME(3) NULL, + `T3` DATETIME(6) NULL, + `T4` DATETIME(6) NULL, + `T5` DATETIME(6) NULL, + `T6` TEXT NULL, + `T7` TEXT NULL + ) + DISTRIBUTED BY HASH(`ID`) BUCKETS 10 + PROPERTIES ( + "replication_allocation" = "tag.location.default: 1" + ); + """ + sql """switch ${catalog_name}""" sql """ use ${ex_db_name}""" @@ -98,6 +144,24 @@ suite("test_oracle_jdbc_catalog", "p0,external,oracle,external_docker,external_d sql """ insert into ${test_insert} select * from ${test_insert} where id = '${uuid2}' """ order_qt_test_insert3 """ select name, age from ${test_insert} where id = '${uuid2}' order by age """ + // test select all types + order_qt_select_all_types """select * from ${test_all_types}; """ + + // test test ctas + sql """ drop table if exists internal.${internal_db_name}.${test_ctas} """ + sql """ create table internal.${internal_db_name}.${test_ctas} + PROPERTIES("replication_num" = "1") + AS select * from ${test_all_types}; + """ + + order_qt_ctas """select * from internal.${internal_db_name}.${test_ctas};""" + + order_qt_ctas_desc """desc internal.${internal_db_name}.${test_ctas};""" + + // test insert into internal.db.tbl + sql """ insert into internal.${internal_db_name}.${test_insert_all_types} select * from ${test_all_types}; """ + order_qt_select_insert_all_types """ select * from internal.${internal_db_name}.${test_insert_all_types} order by id; """ + sql """drop catalog if exists ${catalog_name} """ // test only_specified_database argument diff --git a/regression-test/suites/external_table_p0/jdbc/test_pg_jdbc_catalog.groovy b/regression-test/suites/external_table_p0/jdbc/test_pg_jdbc_catalog.groovy index f92bb37be68cf9..0df873e96ac8cd 100644 --- a/regression-test/suites/external_table_p0/jdbc/test_pg_jdbc_catalog.groovy +++ b/regression-test/suites/external_table_p0/jdbc/test_pg_jdbc_catalog.groovy @@ -29,6 +29,9 @@ suite("test_pg_jdbc_catalog", "p0,external,pg,external_docker,external_docker_pg String pg_port = context.config.otherConfigs.get("pg_14_port"); String inDorisTable = "test_pg_jdbc_doris_in_tb"; String test_insert = "test_insert"; + String test_all_types = "test_all_types"; + String test_insert_all_types = "test_insert_all_types"; + String test_ctas = "test_ctas"; sql """create database if not exists ${internal_db_name}; """ @@ -51,6 +54,38 @@ suite("test_pg_jdbc_catalog", "p0,external,pg,external_docker,external_docker_pg ) DISTRIBUTED BY HASH(id) BUCKETS 10 PROPERTIES("replication_num" = "1"); """ + sql """ drop table if exists ${internal_db_name}.${test_insert_all_types} """ + sql """ + CREATE TABLE ${internal_db_name}.${test_insert_all_types} ( + `id` INT NOT NULL, + `char_value` VARCHAR(*) NULL, + `varchar_value` TEXT NULL, + `date_value` DATE NULL, + `smallint_value` SMALLINT NULL, + `int_value` INT NULL, + `bigint_value` BIGINT NULL, + `timestamp_value` DATETIME(6) NULL, + `decimal_value` DECIMAL(10, 3) NULL, + `bit_value` BOOLEAN NULL, + `real_value` FLOAT NULL, + `cidr_value` TEXT NULL, + `inet_value` TEXT NULL, + `macaddr_value` TEXT NULL, + `bitn_value` TEXT NULL, + `bitnv_value` TEXT NULL, + `serial4_value` INT NOT NULL, + `jsonb_value` JSON NULL, + `point_value` TEXT NULL, + `line_value` TEXT NULL, + `lseg_value` TEXT NULL, + `box_value` TEXT NULL, + `path_value` TEXT NULL, + `polygon_value` TEXT NULL, + `circle_value` TEXT NULL + ) + DISTRIBUTED BY HASH(`id`) BUCKETS 10 + PROPERTIES("replication_num" = "1"); + """ sql """switch ${catalog_name}""" sql """ use ${ex_schema_name}""" @@ -105,6 +140,25 @@ suite("test_pg_jdbc_catalog", "p0,external,pg,external_docker,external_docker_pg sql """ insert into ${test_insert} select * from ${test_insert} where id = '${uuid2}' """ order_qt_test_insert3 """ select name, age from ${test_insert} where id = '${uuid2}' order by age """ + // test select all types + order_qt_select_all_types """select * from ${test_all_types}; """ + + // test test ctas + sql """ drop table if exists internal.${internal_db_name}.${test_ctas} """ + sql """ create table internal.${internal_db_name}.${test_ctas} + PROPERTIES("replication_num" = "1") + AS select * from ${test_all_types}; + """ + + order_qt_ctas """select * from internal.${internal_db_name}.${test_ctas};""" + + order_qt_ctas_desc """desc internal.${internal_db_name}.${test_ctas};""" + + // test insert into internal.db.tbl + sql """ insert into internal.${internal_db_name}.${test_insert_all_types} select * from ${test_all_types}; """ + order_qt_select_insert_all_types """ select * from internal.${internal_db_name}.${test_insert_all_types} order by id; """ + + sql """drop catalog if exists ${catalog_name} """ // test only_specified_database argument From d1438a856323bb793bfd800ed6fb575febb7a477 Mon Sep 17 00:00:00 2001 From: Qi Chen Date: Thu, 9 Nov 2023 12:05:43 +0800 Subject: [PATCH 77/88] [Fix](orc-reader) Fix orc complex types when late materialization was turned on by disabling late materialization in this case. (#26548) Fix orc complex types when late materialization was turned on in orc reader by disabling late materialization in this case. --- be/src/vec/exec/format/orc/vorc_reader.cpp | 10 +++++++++- be/src/vec/exec/format/orc/vorc_reader.h | 1 + .../external_table_p0/hive/test_hive_basic_type.out | 12 ++++++++++++ .../hive/test_hive_basic_type.groovy | 3 +++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/be/src/vec/exec/format/orc/vorc_reader.cpp b/be/src/vec/exec/format/orc/vorc_reader.cpp index dd5713abebe354..214cbe0b57f4fb 100644 --- a/be/src/vec/exec/format/orc/vorc_reader.cpp +++ b/be/src/vec/exec/format/orc/vorc_reader.cpp @@ -734,6 +734,13 @@ Status OrcReader::set_fill_columns( } } + for (auto& each : _tuple_descriptor->slots()) { + PrimitiveType column_type = each->col_type(); + if (column_type == TYPE_ARRAY || column_type == TYPE_MAP || column_type == TYPE_STRUCT) { + _has_complex_type = true; + } + } + for (auto& kv : partition_columns) { auto iter = predicate_columns.find(kv.first); if (iter == predicate_columns.end()) { @@ -754,7 +761,8 @@ Status OrcReader::set_fill_columns( } } - if (_enable_lazy_mat && _lazy_read_ctx.predicate_columns.first.size() > 0 && + if (!_has_complex_type && _enable_lazy_mat && + _lazy_read_ctx.predicate_columns.first.size() > 0 && _lazy_read_ctx.lazy_read_columns.size() > 0) { _lazy_read_ctx.can_lazy_read = true; } diff --git a/be/src/vec/exec/format/orc/vorc_reader.h b/be/src/vec/exec/format/orc/vorc_reader.h index 11cdc72bd7ee0f..eaf8d34be20ce8 100644 --- a/be/src/vec/exec/format/orc/vorc_reader.h +++ b/be/src/vec/exec/format/orc/vorc_reader.h @@ -552,6 +552,7 @@ class OrcReader : public GenericReader { std::shared_ptr _obj_pool; std::unique_ptr _string_dict_filter; bool _is_dict_cols_converted; + bool _has_complex_type = false; }; class ORCFileInputStream : public orc::InputStream { diff --git a/regression-test/data/external_table_p0/hive/test_hive_basic_type.out b/regression-test/data/external_table_p0/hive/test_hive_basic_type.out index e92cb296ccbc94..0398050f02bf67 100644 --- a/regression-test/data/external_table_p0/hive/test_hive_basic_type.out +++ b/regression-test/data/external_table_p0/hive/test_hive_basic_type.out @@ -169,3 +169,15 @@ test DATETIME(6) Yes true \N -- !36 -- \N \N \N \N \N \N \N \N \N test test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa test 3 4 5.1 6.2 true false -1.2 12.30 -1234.5678 123456789.12340000 -1234567890.12345678 1234567890123456789012.1234567800000000 test2 {"test":"test"} {"test":"test"} {"test":"test"} {3:3} {4:4} {5:5} {6:6} {1:1} {-1.2:-1.2} {12.30:12.30} {-1234.5678:-1234.5678} {123456789.12340000:123456789.12340000} {-1234567890.12345678:-1234567890.12345678} {1234567890123456789012.1234567800000000:1234567890123456789012.1234567800000000} ["test"] [3] [4] [5] [6] [1] ["test"] ["test"] [-1.2] [12.30] [-1234.5678] [123456789.12340000] [-1234567890.12345678] [1234567890123456789012.1234567800000000] {"s_bigint": 1} {"test":[{"s_int": 1}]} {"struct_field": ["1", "2", "3"]} {"struct_field_null": null, "struct_field_null2": null} {"struct_non_nulls_after_nulls1": null, "struct_non_nulls_after_nulls2": "some string"} {"struct_field1": null, "struct_field2": "some string", "strict_field3": {"nested_struct_field1": null, "nested_struct_field2": "nested_string2"}} {"k1":"v1", "k2":null, "k3":"v3"} [null, "test"] ["test-1", null, "test-2"] ["test", null] [null, null, null] +-- !41 -- +\N \N \N \N \N \N \N \N \N \N test test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa test 1 2 3 4 5.1 6.2 true false 2011-05-06 2011-05-06T07:08:09.123 -1.2 12.30 -1234.5678 123456789.12340000 -1234567890.12345678 1234567890123456789012.1234567800000000 test2 {"test":"test"} {1:1} {"test":"test"} {"test":"test"} {2:2} {3:3} {4:4} {5:5} {6:6} {1:1} {"2011-05-06":"2011-05-06"} {"2011-05-06 07:08:09.123000":"2011-05-06 07:08:09.123000"} {-1.2:-1.2} {12.30:12.30} {-1234.5678:-1234.5678} {123456789.12340000:123456789.12340000} {-1234567890.12345678:-1234567890.12345678} {1234567890123456789012.1234567800000000:1234567890123456789012.1234567800000000} [] ["test"] [1] [2] [3] [4] [5] [6] [1] ["test"] ["test"] ["2011-05-06"] ["2011-05-06 07:08:09.123000"] [-1.2] [12.30] [-1234.5678] [123456789.12340000] [-1234567890.12345678] [1234567890123456789012.1234567800000000] {"s_bigint": 1} {"test":[{"s_int": 1}]} {"struct_field": ["1", "2", "3"]} {"struct_field_null": null, "struct_field_null2": null} {"struct_non_nulls_after_nulls1": null, "struct_non_nulls_after_nulls2": "some string"} {"struct_field1": null, "struct_field2": "some string", "strict_field3": {"nested_struct_field1": null, "nested_struct_field2": "nested_string2"}} {"k1":"v1", "k2":null, "k3":"v3"} [null, "test"] ["test-1", null, "test-2"] ["test", null] [null, null, null] +\N \N \N \N \N \N \N \N \N \N test test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa test 1 2 3 4 5.1 6.2 true false 2011-05-06 2011-05-06T07:08:09.123 -1.2 12.30 -1234.5678 123456789.12340000 -1234567890.12345678 1234567890123456789012.1234567800000000 test2 {"test":"test"} {1:1} {"test":"test"} {"test":"test"} {2:2} {3:3} {4:4} {5:5} {6:6} {1:1} {"2011-05-06":"2011-05-06"} {"2011-05-06 07:08:09.123000":"2011-05-06 07:08:09.123000"} {-1.2:-1.2} {12.30:12.30} {-1234.5678:-1234.5678} {123456789.12340000:123456789.12340000} {-1234567890.12345678:-1234567890.12345678} {1234567890123456789012.1234567800000000:1234567890123456789012.1234567800000000} [] ["test"] [1] [2] [3] [4] [5] [6] [1] ["test"] ["test"] ["2011-05-06"] ["2011-05-06 07:08:09.123000"] [-1.2] [12.30] [-1234.5678] [123456789.12340000] [-1234567890.12345678] [1234567890123456789012.1234567800000000] {"s_bigint": 1} {"test":[{"s_int": 1}]} {"struct_field": ["1", "2", "3"]} {"struct_field_null": null, "struct_field_null2": null} {"struct_non_nulls_after_nulls1": null, "struct_non_nulls_after_nulls2": "some string"} {"struct_field1": null, "struct_field2": "some string", "strict_field3": {"nested_struct_field1": null, "nested_struct_field2": "nested_string2"}} {"k1":"v1", "k2":null, "k3":"v3"} [null, "test"] ["test-1", null, "test-2"] ["test", null] [null, null, null] +\N \N \N \N \N \N \N \N \N \N test test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa test 1 2 3 4 5.1 6.2 true false 2011-05-06 2011-05-06T07:08:09.123 -1.2 12.30 -1234.5678 123456789.12340000 -1234567890.12345678 1234567890123456789012.1234567800000000 test2 {"test":"test"} {1:1} {"test":"test"} {"test":"test"} {2:2} {3:3} {4:4} {5:5} {6:6} {1:1} {"2011-05-06":"2011-05-06"} {"2011-05-06 07:08:09.123000":"2011-05-06 07:08:09.123000"} {-1.2:-1.2} {12.30:12.30} {-1234.5678:-1234.5678} {123456789.12340000:123456789.12340000} {-1234567890.12345678:-1234567890.12345678} {1234567890123456789012.1234567800000000:1234567890123456789012.1234567800000000} [] ["test"] [1] [2] [3] [4] [5] [6] [1] ["test"] ["test"] ["2011-05-06"] ["2011-05-06 07:08:09.123000"] [-1.2] [12.30] [-1234.5678] [123456789.12340000] [-1234567890.12345678] [1234567890123456789012.1234567800000000] {"s_bigint": 1} {"test":[{"s_int": 1}]} {"struct_field": ["1", "2", "3"]} {"struct_field_null": null, "struct_field_null2": null} {"struct_non_nulls_after_nulls1": null, "struct_non_nulls_after_nulls2": "some string"} {"struct_field1": null, "struct_field2": "some string", "strict_field3": {"nested_struct_field1": null, "nested_struct_field2": "nested_string2"}} {"k1":"v1", "k2":null, "k3":"v3"} [null, "test"] ["test-1", null, "test-2"] ["test", null] [null, null, null] +\N \N \N \N \N \N \N \N \N \N test test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa test 1 2 3 4 5.1 6.2 true false 2011-05-06 2011-05-06T07:08:09.123 -1.2 12.30 -1234.5678 123456789.12340000 -1234567890.12345678 1234567890123456789012.1234567800000000 test2 {"test":"test"} {1:1} {"test":"test"} {"test":"test"} {2:2} {3:3} {4:4} {5:5} {6:6} {1:1} {"2011-05-06":"2011-05-06"} {"2011-05-06 07:08:09.123000":"2011-05-06 07:08:09.123000"} {-1.2:-1.2} {12.30:12.30} {-1234.5678:-1234.5678} {123456789.12340000:123456789.12340000} {-1234567890.12345678:-1234567890.12345678} {1234567890123456789012.1234567800000000:1234567890123456789012.1234567800000000} [] ["test"] [1] [2] [3] [4] [5] [6] [1] ["test"] ["test"] ["2011-05-06"] ["2011-05-06 07:08:09.123000"] [-1.2] [12.30] [-1234.5678] [123456789.12340000] [-1234567890.12345678] [1234567890123456789012.1234567800000000] {"s_bigint": 1} {"test":[{"s_int": 1}]} {"struct_field": ["1", "2", "3"]} {"struct_field_null": null, "struct_field_null2": null} {"struct_non_nulls_after_nulls1": null, "struct_non_nulls_after_nulls2": "some string"} {"struct_field1": null, "struct_field2": "some string", "strict_field3": {"nested_struct_field1": null, "nested_struct_field2": "nested_string2"}} {"k1":"v1", "k2":null, "k3":"v3"} [null, "test"] ["test-1", null, "test-2"] ["test", null] [null, null, null] +\N \N \N \N \N \N \N \N \N \N test test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa test 1 2 3 4 5.1 6.2 true false 2011-05-06 2011-05-06T07:08:09.123 -1.2 12.30 -1234.5678 123456789.12340000 -1234567890.12345678 1234567890123456789012.1234567800000000 test2 {"test":"test"} {1:1} {"test":"test"} {"test":"test"} {2:2} {3:3} {4:4} {5:5} {6:6} {1:1} {"2011-05-06":"2011-05-06"} {"2011-05-06 07:08:09.123000":"2011-05-06 07:08:09.123000"} {-1.2:-1.2} {12.30:12.30} {-1234.5678:-1234.5678} {123456789.12340000:123456789.12340000} {-1234567890.12345678:-1234567890.12345678} {1234567890123456789012.1234567800000000:1234567890123456789012.1234567800000000} [] ["test"] [1] [2] [3] [4] [5] [6] [1] ["test"] ["test"] ["2011-05-06"] ["2011-05-06 07:08:09.123000"] [-1.2] [12.30] [-1234.5678] [123456789.12340000] [-1234567890.12345678] [1234567890123456789012.1234567800000000] {"s_bigint": 1} {"test":[{"s_int": 1}]} {"struct_field": ["1", "2", "3"]} {"struct_field_null": null, "struct_field_null2": null} {"struct_non_nulls_after_nulls1": null, "struct_non_nulls_after_nulls2": "some string"} {"struct_field1": null, "struct_field2": "some string", "strict_field3": {"nested_struct_field1": null, "nested_struct_field2": "nested_string2"}} {"k1":"v1", "k2":null, "k3":"v3"} [null, "test"] ["test-1", null, "test-2"] ["test", null] [null, null, null] +\N \N \N \N \N \N \N \N \N \N test test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa test 1 2 3 4 5.1 6.2 true false 2011-05-06 2011-05-06T07:08:09.123 -1.2 12.30 -1234.5678 123456789.12340000 -1234567890.12345678 1234567890123456789012.1234567800000000 test2 {"test":"test"} {1:1} {"test":"test"} {"test":"test"} {2:2} {3:3} {4:4} {5:5} {6:6} {1:1} {"2011-05-06":"2011-05-06"} {"2011-05-06 07:08:09.123000":"2011-05-06 07:08:09.123000"} {-1.2:-1.2} {12.30:12.30} {-1234.5678:-1234.5678} {123456789.12340000:123456789.12340000} {-1234567890.12345678:-1234567890.12345678} {1234567890123456789012.1234567800000000:1234567890123456789012.1234567800000000} [] ["test"] [1] [2] [3] [4] [5] [6] [1] ["test"] ["test"] ["2011-05-06"] ["2011-05-06 07:08:09.123000"] [-1.2] [12.30] [-1234.5678] [123456789.12340000] [-1234567890.12345678] [1234567890123456789012.1234567800000000] {"s_bigint": 1} {"test":[{"s_int": 1}]} {"struct_field": ["1", "2", "3"]} {"struct_field_null": null, "struct_field_null2": null} {"struct_non_nulls_after_nulls1": null, "struct_non_nulls_after_nulls2": "some string"} {"struct_field1": null, "struct_field2": "some string", "strict_field3": {"nested_struct_field1": null, "nested_struct_field2": "nested_string2"}} {"k1":"v1", "k2":null, "k3":"v3"} [null, "test"] ["test-1", null, "test-2"] ["test", null] [null, null, null] +\N \N \N \N \N \N \N \N \N \N test test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa test 1 2 3 4 5.1 6.2 true false 2011-05-06 2011-05-06T07:08:09.123 -1.2 12.30 -1234.5678 123456789.12340000 -1234567890.12345678 1234567890123456789012.1234567800000000 test2 {"test":"test"} {1:1} {"test":"test"} {"test":"test"} {2:2} {3:3} {4:4} {5:5} {6:6} {1:1} {"2011-05-06":"2011-05-06"} {"2011-05-06 07:08:09.123000":"2011-05-06 07:08:09.123000"} {-1.2:-1.2} {12.30:12.30} {-1234.5678:-1234.5678} {123456789.12340000:123456789.12340000} {-1234567890.12345678:-1234567890.12345678} {1234567890123456789012.1234567800000000:1234567890123456789012.1234567800000000} [] ["test"] [1] [2] [3] [4] [5] [6] [1] ["test"] ["test"] ["2011-05-06"] ["2011-05-06 07:08:09.123000"] [-1.2] [12.30] [-1234.5678] [123456789.12340000] [-1234567890.12345678] [1234567890123456789012.1234567800000000] {"s_bigint": 1} {"test":[{"s_int": 1}]} {"struct_field": ["1", "2", "3"]} {"struct_field_null": null, "struct_field_null2": null} {"struct_non_nulls_after_nulls1": null, "struct_non_nulls_after_nulls2": "some string"} {"struct_field1": null, "struct_field2": "some string", "strict_field3": {"nested_struct_field1": null, "nested_struct_field2": "nested_string2"}} {"k1":"v1", "k2":null, "k3":"v3"} [null, "test"] ["test-1", null, "test-2"] ["test", null] [null, null, null] +\N \N \N \N \N \N \N \N \N \N test test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa test 1 2 3 4 5.1 6.2 true false 2011-05-06 2011-05-06T07:08:09.123 -1.2 12.30 -1234.5678 123456789.12340000 -1234567890.12345678 1234567890123456789012.1234567800000000 test2 {"test":"test"} {1:1} {"test":"test"} {"test":"test"} {2:2} {3:3} {4:4} {5:5} {6:6} {1:1} {"2011-05-06":"2011-05-06"} {"2011-05-06 07:08:09.123000":"2011-05-06 07:08:09.123000"} {-1.2:-1.2} {12.30:12.30} {-1234.5678:-1234.5678} {123456789.12340000:123456789.12340000} {-1234567890.12345678:-1234567890.12345678} {1234567890123456789012.1234567800000000:1234567890123456789012.1234567800000000} [] ["test"] [1] [2] [3] [4] [5] [6] [1] ["test"] ["test"] ["2011-05-06"] ["2011-05-06 07:08:09.123000"] [-1.2] [12.30] [-1234.5678] [123456789.12340000] [-1234567890.12345678] [1234567890123456789012.1234567800000000] {"s_bigint": 1} {"test":[{"s_int": 1}]} {"struct_field": ["1", "2", "3"]} {"struct_field_null": null, "struct_field_null2": null} {"struct_non_nulls_after_nulls1": null, "struct_non_nulls_after_nulls2": "some string"} {"struct_field1": null, "struct_field2": "some string", "strict_field3": {"nested_struct_field1": null, "nested_struct_field2": "nested_string2"}} {"k1":"v1", "k2":null, "k3":"v3"} [null, "test"] ["test-1", null, "test-2"] ["test", null] [null, null, null] +\N \N \N \N \N \N \N \N \N \N test test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa test 1 2 3 4 5.1 6.2 true false 2011-05-06 2011-05-06T07:08:09.123 -1.2 12.30 -1234.5678 123456789.12340000 -1234567890.12345678 1234567890123456789012.1234567800000000 test2 {"test":"test"} {1:1} {"test":"test"} {"test":"test"} {2:2} {3:3} {4:4} {5:5} {6:6} {1:1} {"2011-05-06":"2011-05-06"} {"2011-05-06 07:08:09.123000":"2011-05-06 07:08:09.123000"} {-1.2:-1.2} {12.30:12.30} {-1234.5678:-1234.5678} {123456789.12340000:123456789.12340000} {-1234567890.12345678:-1234567890.12345678} {1234567890123456789012.1234567800000000:1234567890123456789012.1234567800000000} [] ["test"] [1] [2] [3] [4] [5] [6] [1] ["test"] ["test"] ["2011-05-06"] ["2011-05-06 07:08:09.123000"] [-1.2] [12.30] [-1234.5678] [123456789.12340000] [-1234567890.12345678] [1234567890123456789012.1234567800000000] {"s_bigint": 1} {"test":[{"s_int": 1}]} {"struct_field": ["1", "2", "3"]} {"struct_field_null": null, "struct_field_null2": null} {"struct_non_nulls_after_nulls1": null, "struct_non_nulls_after_nulls2": "some string"} {"struct_field1": null, "struct_field2": "some string", "strict_field3": {"nested_struct_field1": null, "nested_struct_field2": "nested_string2"}} {"k1":"v1", "k2":null, "k3":"v3"} [null, "test"] ["test-1", null, "test-2"] ["test", null] [null, null, null] +\N \N \N \N \N \N \N \N \N \N test test aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa test 1 2 3 4 5.1 6.2 true false 2011-05-06 2011-05-06T07:08:09.123 -1.2 12.30 -1234.5678 123456789.12340000 -1234567890.12345678 1234567890123456789012.1234567800000000 test2 {"test":"test"} {1:1} {"test":"test"} {"test":"test"} {2:2} {3:3} {4:4} {5:5} {6:6} {1:1} {"2011-05-06":"2011-05-06"} {"2011-05-06 07:08:09.123000":"2011-05-06 07:08:09.123000"} {-1.2:-1.2} {12.30:12.30} {-1234.5678:-1234.5678} {123456789.12340000:123456789.12340000} {-1234567890.12345678:-1234567890.12345678} {1234567890123456789012.1234567800000000:1234567890123456789012.1234567800000000} [] ["test"] [1] [2] [3] [4] [5] [6] [1] ["test"] ["test"] ["2011-05-06"] ["2011-05-06 07:08:09.123000"] [-1.2] [12.30] [-1234.5678] [123456789.12340000] [-1234567890.12345678] [1234567890123456789012.1234567800000000] {"s_bigint": 1} {"test":[{"s_int": 1}]} {"struct_field": ["1", "2", "3"]} {"struct_field_null": null, "struct_field_null2": null} {"struct_non_nulls_after_nulls1": null, "struct_non_nulls_after_nulls2": "some string"} {"struct_field1": null, "struct_field2": "some string", "strict_field3": {"nested_struct_field1": null, "nested_struct_field2": "nested_string2"}} {"k1":"v1", "k2":null, "k3":"v3"} [null, "test"] ["test-1", null, "test-2"] ["test", null] [null, null, null] + diff --git a/regression-test/suites/external_table_p0/hive/test_hive_basic_type.groovy b/regression-test/suites/external_table_p0/hive/test_hive_basic_type.groovy index 392a1a003cf457..bf58eb163c7554 100644 --- a/regression-test/suites/external_table_p0/hive/test_hive_basic_type.groovy +++ b/regression-test/suites/external_table_p0/hive/test_hive_basic_type.groovy @@ -105,6 +105,9 @@ suite("test_hive_basic_type", "external_docker,hive,external_docker_hive,p0,exte // hive tables in rcbinary format are not supported //order_qt_37 """select * from ${catalog_name}.${ex_db_name}.rcbinary_all_types limit 1;""" + // orc_all_types_t predicate test + order_qt_41 """select * from ${catalog_name}.${ex_db_name}.orc_all_types_t where t_int = 3;""" + //sql """drop catalog if exists ${catalog_name} """ } } From 57ed781bb66b314be7850c6418c6ca7e5b51e2d7 Mon Sep 17 00:00:00 2001 From: Tiewei Fang <43782773+BePPPower@users.noreply.github.com> Date: Thu, 9 Nov 2023 12:09:32 +0800 Subject: [PATCH 78/88] [fix](regression-test) Add tvf regression tests (#26455) --- .../tvf/queries/test_queries_tvf.out | 4 + .../external_table_p0/tvf/test_s3_tvf.out | 29 +++++ .../tvf/test_iceberg_meta.out | 22 ++++ .../tvf/queries/test_queries_tvf.groovy | 37 ++++++ .../external_table_p0/tvf/test_numbers.groovy | 30 ++--- .../external_table_p0/tvf/test_s3_tvf.groovy | 120 ++++++++++++++++++ .../tvf/test_iceberg_meta.groovy | 51 ++++++++ 7 files changed, 278 insertions(+), 15 deletions(-) create mode 100644 regression-test/data/external_table_p0/tvf/queries/test_queries_tvf.out create mode 100644 regression-test/data/external_table_p0/tvf/test_s3_tvf.out create mode 100644 regression-test/data/external_table_p2/tvf/test_iceberg_meta.out create mode 100644 regression-test/suites/external_table_p0/tvf/queries/test_queries_tvf.groovy create mode 100644 regression-test/suites/external_table_p0/tvf/test_s3_tvf.groovy create mode 100644 regression-test/suites/external_table_p2/tvf/test_iceberg_meta.groovy diff --git a/regression-test/data/external_table_p0/tvf/queries/test_queries_tvf.out b/regression-test/data/external_table_p0/tvf/queries/test_queries_tvf.out new file mode 100644 index 00000000000000..6f7e7cf46ed2a3 --- /dev/null +++ b/regression-test/data/external_table_p0/tvf/queries/test_queries_tvf.out @@ -0,0 +1,4 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select -- +1 doris 10 + diff --git a/regression-test/data/external_table_p0/tvf/test_s3_tvf.out b/regression-test/data/external_table_p0/tvf/test_s3_tvf.out new file mode 100644 index 00000000000000..3128c590bc8506 --- /dev/null +++ b/regression-test/data/external_table_p0/tvf/test_s3_tvf.out @@ -0,0 +1,29 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !select_base -- +1 doris1 18 +2 doris2 19 +3 doris3 99 +4 doris4 \N +5 doris5 15 + +-- !select_1 -- +1 doris1 18 +2 doris2 19 +3 doris3 99 +4 doris4 \N +5 doris5 15 + +-- !select_2 -- +1 doris1 18 +2 doris2 19 +3 doris3 99 +4 doris4 \N +5 doris5 15 + +-- !select_3 -- +1 doris1 18 +2 doris2 19 +3 doris3 99 +4 doris4 \N +5 doris5 15 + diff --git a/regression-test/data/external_table_p2/tvf/test_iceberg_meta.out b/regression-test/data/external_table_p2/tvf/test_iceberg_meta.out new file mode 100644 index 00000000000000..b62e2d7510aabb --- /dev/null +++ b/regression-test/data/external_table_p2/tvf/test_iceberg_meta.out @@ -0,0 +1,22 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !q01 -- +2879562 + +-- !q02 -- +1 +11 +3 +5 +6 +7 +8 + +-- !tvf_1 -- +2023-10-16T21:01:06 4012471924714711043 5784892960796156942 append +2023-10-16T21:01:06 5784892960796156942 -1 append +2023-10-16T21:01:06 7235593032487457798 4012471924714711043 append +2023-10-16T21:01:07 1953697979105284524 7235593032487457798 append + +-- !tvf_2 -- +2023-10-16T21:01:06 7235593032487457798 4012471924714711043 append + diff --git a/regression-test/suites/external_table_p0/tvf/queries/test_queries_tvf.groovy b/regression-test/suites/external_table_p0/tvf/queries/test_queries_tvf.groovy new file mode 100644 index 00000000000000..95cd0d3aacabab --- /dev/null +++ b/regression-test/suites/external_table_p0/tvf/queries/test_queries_tvf.groovy @@ -0,0 +1,37 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_queries_tvf","p0,external,tvf,external_docker") { + def table_name = "test_queries_tvf" + sql """ DROP TABLE IF EXISTS ${table_name} """ + sql """ + CREATE TABLE IF NOT EXISTS ${table_name} ( + `user_id` LARGEINT NOT NULL COMMENT "用户id", + `name` STRING COMMENT "用户名称", + `age` INT COMMENT "用户年龄", + ) + DISTRIBUTED BY HASH(user_id) PROPERTIES("replication_num" = "1"); + """ + + sql """insert into ${table_name} values (1, 'doris', 10);""" + + sql """select * from ${table_name};""" + + def res = sql """ select QueryId from queries() where `Sql` like "%${table_name}%"; """ + logger.info("res = " + res) + assertEquals(2, res.size()) +} \ No newline at end of file diff --git a/regression-test/suites/external_table_p0/tvf/test_numbers.groovy b/regression-test/suites/external_table_p0/tvf/test_numbers.groovy index 0bad88ecc99683..6dc09a4f5dfa61 100644 --- a/regression-test/suites/external_table_p0/tvf/test_numbers.groovy +++ b/regression-test/suites/external_table_p0/tvf/test_numbers.groovy @@ -1,19 +1,19 @@ // Licensed to the Apache Software Foundation (ASF) under one - // or more contributor license agreements. See the NOTICE file - // distributed with this work for additional information - // regarding copyright ownership. The ASF licenses this file - // to you under the Apache License, Version 2.0 (the - // "License"); you may not use this file except in compliance - // with the License. You may obtain a copy of the License at - // - // http://www.apache.org/licenses/LICENSE-2.0 - // - // Unless required by applicable law or agreed to in writing, - // software distributed under the License is distributed on an - // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - // KIND, either express or implied. See the License for the - // specific language governing permissions and limitations - // under the License. +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. suite("test_numbers","p0,external,external_docker") { diff --git a/regression-test/suites/external_table_p0/tvf/test_s3_tvf.groovy b/regression-test/suites/external_table_p0/tvf/test_s3_tvf.groovy new file mode 100644 index 00000000000000..273b61a716dcba --- /dev/null +++ b/regression-test/suites/external_table_p0/tvf/test_s3_tvf.groovy @@ -0,0 +1,120 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_s3_tvf", "p0") { + // open nereids + sql """ set enable_nereids_planner=true """ + sql """ set enable_fallback_to_original_planner=false """ + + String ak = getS3AK() + String sk = getS3SK() + String s3_endpoint = getS3Endpoint() + String region = getS3Region() + String bucket = context.config.otherConfigs.get("s3BucketName"); + + + def export_table_name = "test_s3_tvf_export_test" + def outFilePath = "${bucket}/est_s3_tvf/export_test/exp_" + + + def create_table = {table_name -> + sql """ DROP TABLE IF EXISTS ${table_name} """ + sql """ + CREATE TABLE IF NOT EXISTS ${table_name} ( + `user_id` LARGEINT NOT NULL COMMENT "用户id", + `name` STRING COMMENT "用户名称", + `age` INT COMMENT "用户年龄", + ) + DISTRIBUTED BY HASH(user_id) PROPERTIES("replication_num" = "1"); + """ + } + + def outfile_to_S3 = { + // select ... into outfile ... + def res = sql """ + SELECT * FROM ${export_table_name} t ORDER BY user_id + INTO OUTFILE "s3://${outFilePath}" + FORMAT AS ORC + PROPERTIES ( + "s3.endpoint" = "${s3_endpoint}", + "s3.region" = "${region}", + "s3.secret_key"="${sk}", + "s3.access_key" = "${ak}" + ); + """ + + return res[0][3] + } + + // create table to export data + create_table(export_table_name) + + // insert data + sql """ insert into ${export_table_name} values (1, 'doris1', 18); """ + sql """ insert into ${export_table_name} values (2, 'doris2', 19); """ + sql """ insert into ${export_table_name} values (3, 'doris3', 99); """ + sql """ insert into ${export_table_name} values (4, 'doris4', null); """ + sql """ insert into ${export_table_name} values (5, 'doris5', 15); """ + + // test base data + qt_select_base """ SELECT * FROM ${export_table_name} t ORDER BY user_id; """ + + // test outfile to s3 + def outfile_url = outfile_to_S3() + + // 1. normal + try { + order_qt_select_1 """ SELECT * FROM S3 ( + "uri" = "http://${s3_endpoint}${outfile_url.substring(4)}0.orc", + "ACCESS_KEY"= "${ak}", + "SECRET_KEY" = "${sk}", + "format" = "orc", + "region" = "${region}" + ); + """ + } finally { + } + + + // 2. test endpoint property + try { + order_qt_select_2 """ SELECT * FROM S3 ( + "uri" = "http://${outfile_url.substring(5)}0.orc", + "s3.access_key"= "${ak}", + "s3.secret_key" = "${sk}", + "s3.endpoint" = "${s3_endpoint}", + "format" = "orc", + "region" = "${region}" + ); + """ + } finally { + } + + // 3.test use_path_style + try { + order_qt_select_3 """ SELECT * FROM S3 ( + "uri" = "http://${s3_endpoint}${outfile_url.substring(4)}0.orc", + "s3.access_key"= "${ak}", + "s3.secret_key" = "${sk}", + "format" = "orc", + "use_path_style" = "true", + "region" = "${region}" + ); + """ + } finally { + } +} diff --git a/regression-test/suites/external_table_p2/tvf/test_iceberg_meta.groovy b/regression-test/suites/external_table_p2/tvf/test_iceberg_meta.groovy new file mode 100644 index 00000000000000..de13c48727af8b --- /dev/null +++ b/regression-test/suites/external_table_p2/tvf/test_iceberg_meta.groovy @@ -0,0 +1,51 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_iceberg_meta", "p2,external,iceberg,external_remote,external_remote_iceberg") { + String enabled = context.config.otherConfigs.get("enableExternalHiveTest") + if (enabled != null && enabled.equalsIgnoreCase("true")) { + String iceberg_catalog_name = "test_iceberg_meta_tvf" + String extHiveHmsHost = context.config.otherConfigs.get("extHiveHmsHost") + String extHdfsPort = context.config.otherConfigs.get("extHdfsPort") + String db = "multi_catalog" + sql """drop catalog if exists ${iceberg_catalog_name};""" + sql """ + create catalog if not exists ${iceberg_catalog_name} properties ( + 'type'='iceberg', + 'iceberg.catalog.type'='hadoop', + 'warehouse' = 'hdfs://${extHiveHmsHost}:${extHdfsPort}/usr/hive/warehouse/hadoop_catalog' + ); + """ + + sql """switch ${iceberg_catalog_name};""" + sql """ use `${db}`; """ + + order_qt_q01 """ select count(*) from iceberg_hadoop_catalog """ + order_qt_q02 """ select c_custkey from iceberg_hadoop_catalog group by c_custkey order by c_custkey limit 7 """ + + order_qt_tvf_1 """ select committed_at, snapshot_id, parent_id, operation from iceberg_meta( + "table" = "${iceberg_catalog_name}.${db}.multi_partition", + "query_type" = "snapshots"); + """ + + order_qt_tvf_2 """ select committed_at, snapshot_id, parent_id, operation from iceberg_meta( + "table" = "${iceberg_catalog_name}.${db}.multi_partition", + "query_type" = "snapshots") + where snapshot_id = 7235593032487457798; + """ + } +} \ No newline at end of file From 5d52162484b52524ec471611425ab22b6ee30212 Mon Sep 17 00:00:00 2001 From: Jibing-Li <64681310+Jibing-Li@users.noreply.github.com> Date: Thu, 9 Nov 2023 12:12:29 +0800 Subject: [PATCH 79/88] [Test](statistics) Add test cases for external table statistics (#26511) 1. Test for close and open auto collection for external catalog. 2. Test for analyze table table_name (column) and whole table. --- .../doris/datasource/ExternalCatalog.java | 3 + .../doris/datasource/HMSExternalCatalog.java | 4 ++ .../doris/datasource/ExternalCatalogTest.java | 50 +++++++++++++ .../hive/test_hive_statistics_p0.groovy | 72 ++++++++++++++++++- 4 files changed, 128 insertions(+), 1 deletion(-) create mode 100644 fe/fe-core/src/test/java/org/apache/doris/datasource/ExternalCatalogTest.java diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java index e764fdd356f3da..7393a75bac71f8 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/ExternalCatalog.java @@ -104,6 +104,9 @@ public abstract class ExternalCatalog private ExternalSchemaCache schemaCache; private String comment; + public ExternalCatalog() { + } + public ExternalCatalog(long catalogId, String name, InitCatalogLog.Type logType, String comment) { this.id = catalogId; this.name = name; diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/HMSExternalCatalog.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/HMSExternalCatalog.java index 7ca0ac0cff4d4f..408504f5cc2404 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/HMSExternalCatalog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/HMSExternalCatalog.java @@ -70,6 +70,10 @@ public class HMSExternalCatalog extends ExternalCatalog { // 0 means file cache is disabled; >0 means file cache with ttl; public static final int FILE_META_CACHE_TTL_DISABLE_CACHE = 0; + public HMSExternalCatalog() { + catalogProperty = new CatalogProperty(null, null); + } + /** * Default constructor for HMSExternalCatalog. */ diff --git a/fe/fe-core/src/test/java/org/apache/doris/datasource/ExternalCatalogTest.java b/fe/fe-core/src/test/java/org/apache/doris/datasource/ExternalCatalogTest.java new file mode 100644 index 00000000000000..34f5352597ffc8 --- /dev/null +++ b/fe/fe-core/src/test/java/org/apache/doris/datasource/ExternalCatalogTest.java @@ -0,0 +1,50 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.datasource; + +import org.apache.doris.utframe.TestWithFeService; + +import com.google.common.collect.Maps; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; + +public class ExternalCatalogTest extends TestWithFeService { + + @Test + public void testExternalCatalogAutoAnalyze() throws Exception { + HMSExternalCatalog catalog = new HMSExternalCatalog(); + Assertions.assertFalse(catalog.enableAutoAnalyze()); + + HashMap prop = Maps.newHashMap(); + prop.put(ExternalCatalog.ENABLE_AUTO_ANALYZE, "false"); + catalog.modifyCatalogProps(prop); + Assertions.assertFalse(catalog.enableAutoAnalyze()); + + prop = Maps.newHashMap(); + prop.put(ExternalCatalog.ENABLE_AUTO_ANALYZE, "true"); + catalog.modifyCatalogProps(prop); + Assertions.assertTrue(catalog.enableAutoAnalyze()); + + prop = Maps.newHashMap(); + prop.put(ExternalCatalog.ENABLE_AUTO_ANALYZE, "TRUE"); + catalog.modifyCatalogProps(prop); + Assertions.assertTrue(catalog.enableAutoAnalyze()); + } +} diff --git a/regression-test/suites/external_table_p0/hive/test_hive_statistics_p0.groovy b/regression-test/suites/external_table_p0/hive/test_hive_statistics_p0.groovy index 38db4379a9042d..ae041a67b3ac7d 100644 --- a/regression-test/suites/external_table_p0/hive/test_hive_statistics_p0.groovy +++ b/regression-test/suites/external_table_p0/hive/test_hive_statistics_p0.groovy @@ -30,7 +30,33 @@ suite("test_hive_statistics_p0", "all_types,p0,external,hive,external_docker,ext );""" sql """use `${catalog_name}`.`stats_test`""" sql """analyze database stats_test with sync""" - def result = sql """show column stats stats_test1(id);""" + + + def result = sql """show catalog ${catalog_name}""" + for (int i = 0; i < result.size(); i++) { + assertNotEquals("enable.auto.analyze", result[i][0]); + } + sql """alter catalog ${catalog_name} set properties ("enable.auto.analyze" = "true");""" + result = sql """show catalog ${catalog_name}""" + def flag = false; + for (int i = 0; i < result.size(); i++) { + if ("enable.auto.analyze".equalsIgnoreCase((String)result[i][0]) + && "true".equalsIgnoreCase((String)result[i][1])) { + flag = true; + logger.info("enable.auto.analyze has been set to true") + } + } + assertTrue(flag); + sql """alter catalog ${catalog_name} set properties ("enable.auto.analyze" = "false");""" + result = sql """show catalog ${catalog_name}""" + for (int i = 0; i < result.size(); i++) { + if ("enable.auto.analyze".equalsIgnoreCase((String)result[i][0])) { + assertNotEquals("true", ((String)result[i][1]).toLowerCase()); + logger.info("enable.auto.analyze has been set back to false") + } + } + + result = sql """show column stats stats_test1(id);""" assertEquals(1, result.size()) assertEquals("id", result[0][0]) assertEquals("3.0", result[0][1]) @@ -74,8 +100,52 @@ suite("test_hive_statistics_p0", "all_types,p0,external,hive,external_docker,ext assertEquals("\'*\'", result[0][6]) assertEquals("\';\'", result[0][7]) + sql """drop catalog if exists ${catalog_name}""" + + sql """create catalog if not exists ${catalog_name} properties ( + "type"="hms", + 'hive.metastore.uris' = 'thrift://${externalEnvIp}:${hms_port}' + );""" + sql """use `${catalog_name}`.`stats_test`""" + sql """analyze table stats_test1(value) with sync""" + result = sql """show column stats stats_test1(value);""" + assertEquals(1, result.size()) + assertEquals("value", result[0][0]) + assertEquals("3.0", result[0][1]) + assertEquals("3.0", result[0][2]) + assertEquals("0.0", result[0][3]) + assertEquals("15.0", result[0][4]) + assertEquals("5.0", result[0][5]) + assertEquals("\'name1\'" , result[0][6]) + assertEquals("\'name3\'" , result[0][7]) + + result = sql """show column stats stats_test1(id);""" + assertEquals(0, result.size()) + sql """analyze table stats_test2 with sync;""" + result = sql """show column stats stats_test2(id);""" + assertEquals(1, result.size()) + assertEquals("id", result[0][0]) + assertEquals("2.0", result[0][1]) + assertEquals("2.0", result[0][2]) + assertEquals("0.0", result[0][3]) + assertEquals("8.0", result[0][4]) + assertEquals("4.0", result[0][5]) + assertEquals("1", result[0][6]) + assertEquals("2", result[0][7]) + + result = sql """show column stats stats_test2(value);""" + assertEquals(1, result.size()) + assertEquals("value", result[0][0]) + assertEquals("2.0", result[0][1]) + assertEquals("2.0", result[0][2]) + assertEquals("0.0", result[0][3]) + assertEquals("2.0", result[0][4]) + assertEquals("1.0", result[0][5]) + assertEquals("\'*\'", result[0][6]) + assertEquals("\';\'", result[0][7]) sql """drop catalog if exists ${catalog_name}""" + } finally { } } From 33e46ee13d0e0359fab6d2e141f3fd7990db91d2 Mon Sep 17 00:00:00 2001 From: zhengyu Date: Thu, 9 Nov 2023 12:14:37 +0800 Subject: [PATCH 80/88] [enhancement](config) enable single_replica_load by default in BE (#26619) Signed-off-by: freemandealer --- be/src/common/config.cpp | 2 +- docs/en/docs/admin-manual/config/be-config.md | 2 +- docs/en/docs/faq/sql-faq.md | 4 ++-- docs/zh-CN/docs/admin-manual/config/be-config.md | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp index 0ccb48f116e475..29af4d5059a71a 100644 --- a/be/src/common/config.cpp +++ b/be/src/common/config.cpp @@ -457,7 +457,7 @@ DEFINE_Int32(webserver_num_workers, "48"); // Period to update rate counters and sampling counters in ms. DEFINE_mInt32(periodic_counter_update_period_ms, "500"); -DEFINE_Bool(enable_single_replica_load, "false"); +DEFINE_Bool(enable_single_replica_load, "true"); // Number of download workers for single replica load DEFINE_Int32(single_replica_load_download_num_workers, "64"); diff --git a/docs/en/docs/admin-manual/config/be-config.md b/docs/en/docs/admin-manual/config/be-config.md index 0cfbbd8a192006..c11d03345a1a10 100644 --- a/docs/en/docs/admin-manual/config/be-config.md +++ b/docs/en/docs/admin-manual/config/be-config.md @@ -721,7 +721,7 @@ BaseCompaction:546859: #### `enable_single_replica_load` * Description: Whether to enable the single-copy data import function -* Default value: false +* Default value: true #### `load_error_log_reserve_hours` diff --git a/docs/en/docs/faq/sql-faq.md b/docs/en/docs/faq/sql-faq.md index fd40f08bdf1b77..9e38eced91e8ba 100644 --- a/docs/en/docs/faq/sql-faq.md +++ b/docs/en/docs/faq/sql-faq.md @@ -97,5 +97,5 @@ If the `curl 77: Problem with the SSL CA cert` error appears in the be.INFO log. ### Q7. import error:"Message": "[INTERNAL_ERROR]single replica load is disabled on BE." -1. Add parameters in be.conf : enable_single_replica_load = true -2. Restart the BE node. \ No newline at end of file +1. Make sure this parameters `enable_single_replica_load` in be.conf is set true +2. Restart the BE node. diff --git a/docs/zh-CN/docs/admin-manual/config/be-config.md b/docs/zh-CN/docs/admin-manual/config/be-config.md index 36dd0a345c9787..533b7db5f487b3 100644 --- a/docs/zh-CN/docs/admin-manual/config/be-config.md +++ b/docs/zh-CN/docs/admin-manual/config/be-config.md @@ -747,7 +747,7 @@ BaseCompaction:546859: #### `enable_single_replica_load` * 描述: 是否启动单副本数据导入功能 -* 默认值: false +* 默认值: true #### `load_error_log_reserve_hours` From 124a8a9b34d15b6ab6820edb822a7394db42c092 Mon Sep 17 00:00:00 2001 From: zhengyu Date: Thu, 9 Nov 2023 12:21:15 +0800 Subject: [PATCH 81/88] [enhancement](regression) add profile before datev2 insert for debug (#26617) Signed-off-by: freemandealer --- .../schema_change/test_schema_change_datev2_with_delete.groovy | 1 + 1 file changed, 1 insertion(+) diff --git a/regression-test/suites/schema_change/test_schema_change_datev2_with_delete.groovy b/regression-test/suites/schema_change/test_schema_change_datev2_with_delete.groovy index ca2cb666dbb55b..b6a827ebca1e4b 100644 --- a/regression-test/suites/schema_change/test_schema_change_datev2_with_delete.groovy +++ b/regression-test/suites/schema_change/test_schema_change_datev2_with_delete.groovy @@ -16,6 +16,7 @@ // under the License. suite("test_schema_change_datev2_with_delete") { + sql """ SET enable_profile = true """ def tbName = "test_schema_change_datev2_with_delete" def getJobState = { tableName -> def jobStateResult = sql """ SHOW ALTER TABLE COLUMN WHERE IndexName='${tableName}' ORDER BY createtime DESC LIMIT 1 """ From db317841a07f1cca684c5fd4c0ecfbea5fcaf93b Mon Sep 17 00:00:00 2001 From: Jack Drogon Date: Thu, 9 Nov 2023 12:21:43 +0800 Subject: [PATCH 82/88] [hotfix](editlog) Fix upsert replay on follower not contains loadedTableIndexIds (#26597) Signed-off-by: Jack Drogon --- fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java | 1 + .../org/apache/doris/transaction/DatabaseTransactionMgr.java | 1 + 2 files changed, 2 insertions(+) diff --git a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java index d17fbc99c94be8..877b6cc18ea4a2 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/persist/EditLog.java @@ -530,6 +530,7 @@ public static void loadJournal(Env env, Long logId, JournalEntity journal) { Env.getCurrentGlobalTransactionMgr().replayUpsertTransactionState(state); LOG.debug("logid: {}, opcode: {}, tid: {}", logId, opCode, state.getTransactionId()); + // state.loadedTableIndexIds is updated after replay if (state.getTransactionStatus() == TransactionStatus.VISIBLE) { UpsertRecord upsertRecord = new UpsertRecord(logId, state); Env.getCurrentEnv().getBinlogManager().addUpsertRecord(upsertRecord); diff --git a/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java b/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java index e6d266e43eeca8..9b123030465f10 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java +++ b/fe/fe-core/src/main/java/org/apache/doris/transaction/DatabaseTransactionMgr.java @@ -1769,6 +1769,7 @@ private boolean updateCatalogAfterVisible(TransactionState transactionState, Dat tableId, transactionState.getTransactionId(), db.getId()); continue; } + transactionState.addTableIndexes(table); for (PartitionCommitInfo partitionCommitInfo : tableCommitInfo.getIdToPartitionCommitInfo().values()) { long partitionId = partitionCommitInfo.getPartitionId(); long newCommitVersion = partitionCommitInfo.getVersion(); From 0929ad568f88bb3270b12c31ebc3e91001a50ace Mon Sep 17 00:00:00 2001 From: zhengyu Date: Thu, 9 Nov 2023 12:22:13 +0800 Subject: [PATCH 83/88] [fix](regression) move fault-injection data to the right place (#26618) Signed-off-by: freemandealer --- .../test_segcompaction_fault_injection.out | 0 .../test_too_many_segments_fault_injection.out | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename regression-test/data/fault_injection_p0/{fault_injection_p0 => }/test_segcompaction_fault_injection.out (100%) rename regression-test/data/fault_injection_p0/{fault_injection_p0 => }/test_too_many_segments_fault_injection.out (100%) diff --git a/regression-test/data/fault_injection_p0/fault_injection_p0/test_segcompaction_fault_injection.out b/regression-test/data/fault_injection_p0/test_segcompaction_fault_injection.out similarity index 100% rename from regression-test/data/fault_injection_p0/fault_injection_p0/test_segcompaction_fault_injection.out rename to regression-test/data/fault_injection_p0/test_segcompaction_fault_injection.out diff --git a/regression-test/data/fault_injection_p0/fault_injection_p0/test_too_many_segments_fault_injection.out b/regression-test/data/fault_injection_p0/test_too_many_segments_fault_injection.out similarity index 100% rename from regression-test/data/fault_injection_p0/fault_injection_p0/test_too_many_segments_fault_injection.out rename to regression-test/data/fault_injection_p0/test_too_many_segments_fault_injection.out From 84d1c3ba3022b5fde2636f2b624176137d27c956 Mon Sep 17 00:00:00 2001 From: walter Date: Thu, 9 Nov 2023 12:28:16 +0800 Subject: [PATCH 84/88] [Improve](ddl) Use RecycleBin to force drop db/table asynchronously (#26563) --- .../doris/catalog/CatalogRecycleBin.java | 36 ++++++--- .../doris/catalog/TabletInvertedIndex.java | 28 ++++++- .../doris/datasource/InternalCatalog.java | 24 ++---- .../org/apache/doris/catalog/DropDbTest.java | 17 +++-- .../apache/doris/catalog/DropTableTest.java | 15 ++-- .../clone/TabletRepairAndBalanceTest.java | 8 +- .../doris/utframe/TestWithFeService.java | 3 + .../suites/ddl_p0/test_drop_force.groovy | 75 +++++++++++++++++++ 8 files changed, 161 insertions(+), 45 deletions(-) create mode 100644 regression-test/suites/ddl_p0/test_drop_force.groovy diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/CatalogRecycleBin.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/CatalogRecycleBin.java index b28a7fd08d795e..e328270ae134ed 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/CatalogRecycleBin.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/CatalogRecycleBin.java @@ -21,6 +21,7 @@ import org.apache.doris.catalog.TableIf.TableType; import org.apache.doris.common.Config; import org.apache.doris.common.DdlException; +import org.apache.doris.common.FeConstants; import org.apache.doris.common.FeMetaVersion; import org.apache.doris.common.io.Text; import org.apache.doris.common.io.Writable; @@ -55,6 +56,7 @@ public class CatalogRecycleBin extends MasterDaemon implements Writable { private static final Logger LOG = LogManager.getLogger(CatalogRecycleBin.class); + private static final int DEFAULT_INTERVAL_SECONDS = 30; // 30 seconds // erase meta at least after minEraseLatency milliseconds // to avoid erase log ahead of drop log private static final long minEraseLatency = 10 * 60 * 1000; // 10 min @@ -66,7 +68,7 @@ public class CatalogRecycleBin extends MasterDaemon implements Writable { private Map idToRecycleTime; public CatalogRecycleBin() { - super("recycle bin"); + super("recycle bin", FeConstants.runningUnitTest ? 10L : DEFAULT_INTERVAL_SECONDS * 1000L); idToDatabase = Maps.newHashMap(); idToTable = Maps.newHashMap(); idToPartition = Maps.newHashMap(); @@ -124,7 +126,7 @@ private void addRecycledTabletsForPartition(Set recycledTabletSet, Partiti } public synchronized boolean recycleDatabase(Database db, Set tableNames, Set tableIds, - boolean isReplay, long replayRecycleTime) { + boolean isReplay, boolean isForceDrop, long replayRecycleTime) { long recycleTime = 0; if (idToDatabase.containsKey(db.getId())) { LOG.error("db[{}] already in recycle bin.", db.getId()); @@ -137,17 +139,21 @@ public synchronized boolean recycleDatabase(Database db, Set tableNames, // recycle db RecycleDatabaseInfo databaseInfo = new RecycleDatabaseInfo(db, tableNames, tableIds); idToDatabase.put(db.getId(), databaseInfo); - if (!isReplay || replayRecycleTime == 0) { + if (isForceDrop) { + // The 'force drop' database should be recycle immediately. + recycleTime = 0; + } else if (!isReplay || replayRecycleTime == 0) { recycleTime = System.currentTimeMillis(); } else { recycleTime = replayRecycleTime; } idToRecycleTime.put(db.getId(), recycleTime); - LOG.info("recycle db[{}-{}]", db.getId(), db.getFullName()); + LOG.info("recycle db[{}-{}], is force drop: {}", db.getId(), db.getFullName(), isForceDrop); return true; } - public synchronized boolean recycleTable(long dbId, Table table, boolean isReplay, long replayRecycleTime) { + public synchronized boolean recycleTable(long dbId, Table table, boolean isReplay, + boolean isForceDrop, long replayRecycleTime) { long recycleTime = 0; if (idToTable.containsKey(table.getId())) { LOG.error("table[{}] already in recycle bin.", table.getId()); @@ -156,14 +162,17 @@ public synchronized boolean recycleTable(long dbId, Table table, boolean isRepla // recycle table RecycleTableInfo tableInfo = new RecycleTableInfo(dbId, table); - if (!isReplay || replayRecycleTime == 0) { + if (isForceDrop) { + // The 'force drop' table should be recycle immediately. + recycleTime = 0; + } else if (!isReplay || replayRecycleTime == 0) { recycleTime = System.currentTimeMillis(); } else { recycleTime = replayRecycleTime; } idToRecycleTime.put(table.getId(), recycleTime); idToTable.put(table.getId(), tableInfo); - LOG.info("recycle table[{}-{}]", table.getId(), table.getName()); + LOG.info("recycle table[{}-{}], is force drop: {}", table.getId(), table.getName(), isForceDrop); return true; } @@ -419,6 +428,11 @@ public synchronized void replayEraseTable(long tableId) { LOG.info("before replay erase table[{}]", tableId); RecycleTableInfo tableInfo = idToTable.remove(tableId); idToRecycleTime.remove(tableId); + if (tableInfo == null) { + // FIXME(walter): Sometimes `eraseTable` in 'DROP DB ... FORCE' may be executed earlier than + // finish drop db, especially in the case of drop db with many tables. + return; + } Table table = tableInfo.getTable(); if (table.getType() == TableType.OLAP) { Env.getCurrentEnv().onEraseOlapTable((OlapTable) table, true); @@ -537,7 +551,9 @@ public synchronized void replayErasePartition(long partitionId) { public synchronized Database recoverDatabase(String dbName, long dbId) throws DdlException { RecycleDatabaseInfo dbInfo = null; - long recycleTime = -1; + // The recycle time of the force dropped tables and databases will be set to zero, use 1 here to + // skip these databases and tables. + long recycleTime = 1; Iterator> iterator = idToDatabase.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = iterator.next(); @@ -616,7 +632,9 @@ public synchronized boolean recoverTable(Database db, String tableName, long tab String newTableName) throws DdlException { // make sure to get db lock Table table = null; - long recycleTime = -1; + // The recycle time of the force dropped tables and databases will be set to zero, use 1 here to + // skip these databases and tables. + long recycleTime = 1; long dbId = db.getId(); Iterator> iterator = idToTable.entrySet().iterator(); while (iterator.hasNext()) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/catalog/TabletInvertedIndex.java b/fe/fe-core/src/main/java/org/apache/doris/catalog/TabletInvertedIndex.java index c1b7ca293bcda2..c3ba8e625a6a5a 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/catalog/TabletInvertedIndex.java +++ b/fe/fe-core/src/main/java/org/apache/doris/catalog/TabletInvertedIndex.java @@ -822,22 +822,42 @@ public PartitionBalanceInfo(PartitionBalanceInfo info) { // just for ut public Table getReplicaMetaTable() { - return replicaMetaTable; + long stamp = readLock(); + try { + return HashBasedTable.create(replicaMetaTable); + } finally { + readUnlock(stamp); + } } // just for ut public Table getBackingReplicaMetaTable() { - return backingReplicaMetaTable; + long stamp = readLock(); + try { + return HashBasedTable.create(backingReplicaMetaTable); + } finally { + readUnlock(stamp); + } } // just for ut public Table getTabletMetaTable() { - return tabletMetaTable; + long stamp = readLock(); + try { + return HashBasedTable.create(tabletMetaTable); + } finally { + readUnlock(stamp); + } } // just for ut public Map getTabletMetaMap() { - return tabletMetaMap; + long stamp = readLock(); + try { + return new HashMap(tabletMetaMap); + } finally { + readUnlock(stamp); + } } private boolean isLocal(TStorageMedium storageMedium) { diff --git a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java index 9b8985a8c8bbfc..6b1e3d90e60d13 100644 --- a/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java +++ b/fe/fe-core/src/main/java/org/apache/doris/datasource/InternalCatalog.java @@ -478,6 +478,7 @@ public void replayCreateDb(Database db, String newDbName) { public void dropDb(DropDbStmt stmt) throws DdlException { String dbName = stmt.getDbName(); + LOG.info("begin drop database[{}], is force : {}", dbName, stmt.isForceDrop()); // 1. check if database exists if (!tryLock(false)) { @@ -536,12 +537,8 @@ public void dropDb(DropDbStmt stmt) throws DdlException { MetaLockUtils.writeUnlockTables(tableList); } - if (!stmt.isForceDrop()) { - Env.getCurrentRecycleBin().recycleDatabase(db, tableNames, tableIds, false, 0); - recycleTime = Env.getCurrentRecycleBin().getRecycleTimeById(db.getId()); - } else { - Env.getCurrentEnv().eraseDatabase(db.getId(), false); - } + Env.getCurrentRecycleBin().recycleDatabase(db, tableNames, tableIds, false, stmt.isForceDrop(), 0); + recycleTime = Env.getCurrentRecycleBin().getRecycleTimeById(db.getId()); } finally { db.writeUnlock(); } @@ -588,11 +585,7 @@ public void replayDropDb(String dbName, boolean isForceDrop, Long recycleTime) t } finally { MetaLockUtils.writeUnlockTables(tableList); } - if (!isForceDrop) { - Env.getCurrentRecycleBin().recycleDatabase(db, tableNames, tableIds, true, recycleTime); - } else { - Env.getCurrentEnv().eraseDatabase(db.getId(), false); - } + Env.getCurrentRecycleBin().recycleDatabase(db, tableNames, tableIds, true, isForceDrop, recycleTime); Env.getCurrentEnv().getQueryStats().clear(Env.getCurrentEnv().getInternalCatalog().getId(), db.getId()); } finally { db.writeUnlock(); @@ -861,6 +854,7 @@ public void replayRenameDatabase(String dbName, String newDbName) { public void dropTable(DropTableStmt stmt) throws DdlException { String dbName = stmt.getDbName(); String tableName = stmt.getTableName(); + LOG.info("begin to drop table: {} from db: {}, is force: {}", tableName, dbName, stmt.isForceDrop()); // check database Database db = (Database) getDbOrDdlException(dbName); @@ -943,13 +937,7 @@ public boolean unprotectDropTable(Database db, Table table, boolean isForceDrop, } db.dropTable(table.getName()); - if (!isForceDrop) { - Env.getCurrentRecycleBin().recycleTable(db.getId(), table, isReplay, recycleTime); - } else { - if (table.getType() == TableType.OLAP) { - Env.getCurrentEnv().onEraseOlapTable((OlapTable) table, isReplay); - } - } + Env.getCurrentRecycleBin().recycleTable(db.getId(), table, isReplay, isForceDrop, recycleTime); LOG.info("finished dropping table[{}] in db[{}]", table.getName(), db.getFullName()); return true; } diff --git a/fe/fe-core/src/test/java/org/apache/doris/catalog/DropDbTest.java b/fe/fe-core/src/test/java/org/apache/doris/catalog/DropDbTest.java index c262958c6b1d0b..4bc976b3c70d40 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/catalog/DropDbTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/DropDbTest.java @@ -121,15 +121,18 @@ public void testNormalDropDb() throws Exception { @Test public void testForceDropDb() throws Exception { String dropDbSql = "drop database test2 force"; - Database db = Env.getCurrentInternalCatalog().getDbOrMetaException("default_cluster:test2"); - OlapTable table = (OlapTable) db.getTableOrMetaException("tbl1"); - Partition partition = table.getAllPartitions().iterator().next(); - long tabletId = partition.getBaseIndex().getTablets().get(0).getId(); dropDb(dropDbSql); - db = Env.getCurrentInternalCatalog().getDbNullable("default_cluster:test2"); - List replicaList = Env.getCurrentEnv().getTabletInvertedIndex().getReplicasByTabletId(tabletId); + Database db = Env.getCurrentInternalCatalog().getDbNullable("default_cluster:test2"); Assert.assertNull(db); - Assert.assertTrue(replicaList.isEmpty()); + // After unify force and non-force drop db, the replicas will be recycled eventually. + // + // Database db = Env.getCurrentInternalCatalog().getDbOrMetaException("default_cluster:test2"); + // OlapTable table = (OlapTable) db.getTableOrMetaException("tbl1"); + // Partition partition = table.getAllPartitions().iterator().next(); + // long tabletId = partition.getBaseIndex().getTablets().get(0).getId(); + // ... + // List replicaList = Env.getCurrentEnv().getTabletInvertedIndex().getReplicasByTabletId(tabletId); + // Assert.assertTrue(replicaList.isEmpty()); String recoverDbSql = "recover database test2"; RecoverDbStmt recoverDbStmt = (RecoverDbStmt) UtFrameUtils.parseAndAnalyzeStmt(recoverDbSql, connectContext); ExceptionChecker.expectThrowsWithMsg(DdlException.class, diff --git a/fe/fe-core/src/test/java/org/apache/doris/catalog/DropTableTest.java b/fe/fe-core/src/test/java/org/apache/doris/catalog/DropTableTest.java index accb1f7da80da4..97be554d63305c 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/catalog/DropTableTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/catalog/DropTableTest.java @@ -98,14 +98,17 @@ public void testNormalDropTable() throws Exception { @Test public void testForceDropTable() throws Exception { - Database db = Env.getCurrentInternalCatalog().getDbOrMetaException("default_cluster:test"); - OlapTable table = (OlapTable) db.getTableOrMetaException("tbl2"); - Partition partition = table.getAllPartitions().iterator().next(); - long tabletId = partition.getBaseIndex().getTablets().get(0).getId(); String dropTableSql = "drop table test.tbl2 force"; dropTable(dropTableSql); - List replicaList = Env.getCurrentEnv().getTabletInvertedIndex().getReplicasByTabletId(tabletId); - Assert.assertTrue(replicaList.isEmpty()); + // After unify force and non-force drop table, the replicas will be recycled eventually. + // + // Database db = Env.getCurrentInternalCatalog().getDbOrMetaException("default_cluster:test"); + // OlapTable table = (OlapTable) db.getTableOrMetaException("tbl2"); + // Partition partition = table.getAllPartitions().iterator().next(); + // long tabletId = partition.getBaseIndex().getTablets().get(0).getId(); + // ... + // List replicaList = Env.getCurrentEnv().getTabletInvertedIndex().getReplicasByTabletId(tabletId); + // Assert.assertTrue(replicaList.isEmpty()); String recoverDbSql = "recover table test.tbl2"; RecoverTableStmt recoverTableStmt = (RecoverTableStmt) UtFrameUtils.parseAndAnalyzeStmt(recoverDbSql, connectContext); ExceptionChecker.expectThrowsWithMsg(DdlException.class, diff --git a/fe/fe-core/src/test/java/org/apache/doris/clone/TabletRepairAndBalanceTest.java b/fe/fe-core/src/test/java/org/apache/doris/clone/TabletRepairAndBalanceTest.java index b520d73a8bcf2d..ec0779b452d15a 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/clone/TabletRepairAndBalanceTest.java +++ b/fe/fe-core/src/test/java/org/apache/doris/clone/TabletRepairAndBalanceTest.java @@ -417,7 +417,13 @@ public void test() throws Exception { ExceptionChecker.expectThrowsNoException(() -> dropTable(dropStmt1)); ExceptionChecker.expectThrowsNoException(() -> dropTable(dropStmt2)); ExceptionChecker.expectThrowsNoException(() -> dropTable(dropStmt3)); - Assert.assertEquals(0, replicaMetaTable.size()); + Assert.assertNull(db.getTableNullable("tbl1")); + Assert.assertNull(db.getTableNullable("col_tbl1")); + Assert.assertNull(db.getTableNullable("col_tbl2")); + // After unify force and non-force drop table, the indexes will be erase eventually. + while (colocateTableIndex.getAllGroupIds().size() > 0) { + Thread.sleep(1000); + } // set all backends' tag to default for (int i = 0; i < backends.size(); ++i) { diff --git a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java index 62e1e95ec14d85..b5ef93b97a2545 100644 --- a/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java +++ b/fe/fe-core/src/test/java/org/apache/doris/utframe/TestWithFeService.java @@ -746,6 +746,9 @@ private void updateReplicaPathHash() { } Replica replica = cell.getValue(); TabletMeta tabletMeta = Env.getCurrentInvertedIndex().getTabletMeta(cell.getRowKey()); + if (tabletMeta == null) { + continue; + } ImmutableMap diskMap = be.getDisks(); for (DiskInfo diskInfo : diskMap.values()) { if (diskInfo.getStorageMedium() == tabletMeta.getStorageMedium()) { diff --git a/regression-test/suites/ddl_p0/test_drop_force.groovy b/regression-test/suites/ddl_p0/test_drop_force.groovy new file mode 100644 index 00000000000000..565df0b768c430 --- /dev/null +++ b/regression-test/suites/ddl_p0/test_drop_force.groovy @@ -0,0 +1,75 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +// this suite is for creating table with timestamp datatype in defferent +// case. For example: 'year' and 'Year' datatype should also be valid in definition + +suite("sql_force_drop") { + def testTable = "test_force_drop" + + sql "CREATE DATABASE IF NOT EXISTS test_force_drop_database" + sql """ + CREATE TABLE IF NOT EXISTS test_force_drop_database.table1 ( + `actorid` varchar(128), + `gameid` varchar(128), + `eventtime` datetimev2(3) + ) + engine=olap + duplicate key(actorid, gameid, eventtime) + partition by range(eventtime)( + from ("2000-01-01") to ("2021-01-01") interval 1 year, + from ("2021-01-01") to ("2022-01-01") interval 1 MONth, + from ("2022-01-01") to ("2023-01-01") interval 1 WEEK, + from ("2023-01-01") TO ("2023-02-01") interval 1 DAY + ) + distributed by hash(actorid) buckets 1 + properties( + "replication_num"="1", + "light_schema_change"="true", + "compression"="zstd" + ); + """ + sql """ + CREATE TABLE IF NOT EXISTS test_force_drop_database.table2 ( + `actorid` varchar(128), + `gameid` varchar(128), + `eventtime` datetimev2(3) + ) + engine=olap + duplicate key(actorid, gameid, eventtime) + partition by range(eventtime)( + from ("2000-01-01") to ("2021-01-01") interval 1 year, + from ("2021-01-01") to ("2022-01-01") interval 1 MONth, + from ("2022-01-01") to ("2023-01-01") interval 1 WEEK, + from ("2023-01-01") TO ("2023-02-01") interval 1 DAY + ) + distributed by hash(actorid) buckets 1 + properties( + "replication_num"="1", + "light_schema_change"="true", + "compression"="zstd" + ); + """ + + sql " drop table test_force_drop_database.table2 " + sql " recover table test_force_drop_database.table2 " + sql " drop table test_force_drop_database.table2 FORCE" + sql " drop database test_force_drop_database " + sql " recover database test_force_drop_database " + sql " drop database test_force_drop_database FORCE" +} + From 5f62a4462dd670d83cd09349a31125c21686fc71 Mon Sep 17 00:00:00 2001 From: abmdocrt Date: Thu, 9 Nov 2023 12:29:05 +0800 Subject: [PATCH 85/88] [Enhancement](wal) Add wal space back pressure (#26483) --- be/src/common/config.cpp | 7 +++++-- be/src/common/config.h | 3 +++ be/src/olap/wal_manager.cpp | 24 +++++++++++++++++++++++- be/src/olap/wal_manager.h | 4 ++++ be/src/olap/wal_writer.cpp | 20 +++++++++++++++++++- be/src/olap/wal_writer.h | 13 ++++++++++++- be/test/olap/wal_manager_test.cpp | 4 +++- be/test/olap/wal_reader_writer_test.cpp | 5 ++++- 8 files changed, 73 insertions(+), 7 deletions(-) diff --git a/be/src/common/config.cpp b/be/src/common/config.cpp index 29af4d5059a71a..0133a78ecf9c5a 100644 --- a/be/src/common/config.cpp +++ b/be/src/common/config.cpp @@ -1118,8 +1118,11 @@ DEFINE_Bool(ignore_always_true_predicate_for_segment, "true"); // Dir of default timezone files DEFINE_String(default_tzfiles_path, "${DORIS_HOME}/zoneinfo"); -// Max size(bytes) of group commit queues, used for mem back pressure. -DEFINE_Int32(group_commit_max_queue_size, "65536"); +// Max size(bytes) of group commit queues, used for mem back pressure, defult 64M. +DEFINE_Int32(group_commit_max_queue_size, "67108864"); + +// Max size(bytes) of wal disk using, used for disk space back pressure, default 64M. +DEFINE_Int32(wal_max_disk_size, "67108864"); // Ingest binlog work pool size, -1 is disable, 0 is hardware concurrency DEFINE_Int32(ingest_binlog_work_pool_size, "-1"); diff --git a/be/src/common/config.h b/be/src/common/config.h index f0fdf58558c35e..d9276aef9a575f 100644 --- a/be/src/common/config.h +++ b/be/src/common/config.h @@ -1195,6 +1195,9 @@ DECLARE_String(default_tzfiles_path); // Max size(bytes) of group commit queues, used for mem back pressure. DECLARE_Int32(group_commit_max_queue_size); +// Max size(bytes) of wal disk using, used for disk space back pressure. +DECLARE_Int32(wal_max_disk_size); + // Ingest binlog work pool size DECLARE_Int32(ingest_binlog_work_pool_size); diff --git a/be/src/olap/wal_manager.cpp b/be/src/olap/wal_manager.cpp index cf84c4a9661f2e..921f7da8e3897a 100644 --- a/be/src/olap/wal_manager.cpp +++ b/be/src/olap/wal_manager.cpp @@ -19,10 +19,15 @@ #include +#include #include +#include #include +#include +#include #include "io/fs/local_file_system.h" +#include "olap/wal_writer.h" #include "runtime/client_cache.h" #include "runtime/fragment_mgr.h" #include "runtime/plan_fragment_executor.h" @@ -35,11 +40,13 @@ namespace doris { WalManager::WalManager(ExecEnv* exec_env, const std::string& wal_dir_list) : _exec_env(exec_env), _stop_background_threads_latch(1) { doris::vectorized::WalReader::string_split(wal_dir_list, ",", _wal_dirs); + _all_wal_disk_bytes = std::make_shared(0); } WalManager::~WalManager() { LOG(INFO) << "WalManager is destoried"; } + void WalManager::stop() { _stop = true; _stop_background_threads_latch.count_down(); @@ -117,8 +124,12 @@ Status WalManager::create_wal_writer(int64_t wal_id, std::shared_ptr& RETURN_IF_ERROR(io::global_local_filesystem()->create_directory(base_path)); } LOG(INFO) << "create wal " << wal_path; - wal_writer = std::make_shared(wal_path); + wal_writer = std::make_shared(wal_path, _all_wal_disk_bytes); RETURN_IF_ERROR(wal_writer->init()); + { + std::lock_guard wrlock(_wal_lock); + _wal_id_to_writer_map.emplace(wal_id, wal_writer); + } return Status::OK(); } @@ -241,6 +252,17 @@ size_t WalManager::get_wal_table_size(const std::string& table_id) { Status WalManager::delete_wal(int64_t wal_id) { { std::lock_guard wrlock(_wal_lock); + if (_wal_id_to_writer_map.find(wal_id) != _wal_id_to_writer_map.end()) { + _all_wal_disk_bytes->store( + _all_wal_disk_bytes->fetch_sub(_wal_id_to_writer_map[wal_id]->disk_bytes(), + std::memory_order_relaxed), + std::memory_order_relaxed); + _wal_id_to_writer_map[wal_id]->cv.notify_one(); + _wal_id_to_writer_map.erase(wal_id); + } + if (_wal_id_to_writer_map.empty()) { + CHECK_EQ(_all_wal_disk_bytes->load(std::memory_order_relaxed), 0); + } std::string wal_path = _wal_path_map[wal_id]; RETURN_IF_ERROR(io::global_local_filesystem()->delete_file(wal_path)); LOG(INFO) << "delete file=" << wal_path; diff --git a/be/src/olap/wal_manager.h b/be/src/olap/wal_manager.h index f5b49f6ddaf2c2..d8fa4a705278d2 100644 --- a/be/src/olap/wal_manager.h +++ b/be/src/olap/wal_manager.h @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +#include + #include "common/config.h" #include "gen_cpp/FrontendService.h" #include "gen_cpp/FrontendService_types.h" @@ -56,6 +58,8 @@ class WalManager { std::vector _wal_dirs; std::shared_mutex _wal_lock; std::unordered_map _wal_path_map; + std::unordered_map> _wal_id_to_writer_map; + std::shared_ptr _all_wal_disk_bytes; bool _stop = false; }; } // namespace doris \ No newline at end of file diff --git a/be/src/olap/wal_writer.cpp b/be/src/olap/wal_writer.cpp index 7cd427453bb361..085c0f0e31fa07 100644 --- a/be/src/olap/wal_writer.cpp +++ b/be/src/olap/wal_writer.cpp @@ -17,6 +17,9 @@ #include "olap/wal_writer.h" +#include + +#include "common/config.h" #include "io/fs/file_writer.h" #include "io/fs/local_file_system.h" #include "io/fs/path.h" @@ -25,7 +28,12 @@ namespace doris { -WalWriter::WalWriter(const std::string& file_name) : _file_name(file_name) {} +WalWriter::WalWriter(const std::string& file_name, + const std::shared_ptr& all_wal_disk_bytes) + : _file_name(file_name), + _count(0), + _disk_bytes(0), + _all_wal_disk_bytes(all_wal_disk_bytes) {} WalWriter::~WalWriter() {} @@ -44,6 +52,12 @@ Status WalWriter::finalize() { } Status WalWriter::append_blocks(const PBlockArray& blocks) { + { + std::unique_lock l(_mutex); + while (_all_wal_disk_bytes->load(std::memory_order_relaxed) > config::wal_max_disk_size) { + cv.wait_for(l, std::chrono::milliseconds(WalWriter::MAX_WAL_WRITE_WAIT_TIME)); + } + } size_t total_size = 0; for (const auto& block : blocks) { total_size += LENGTH_SIZE + block->ByteSizeLong() + CHECKSUM_SIZE; @@ -62,6 +76,10 @@ Status WalWriter::append_blocks(const PBlockArray& blocks) { offset += CHECKSUM_SIZE; } DCHECK(offset == total_size); + _disk_bytes += total_size; + _all_wal_disk_bytes->store( + _all_wal_disk_bytes->fetch_add(total_size, std::memory_order_relaxed), + std::memory_order_relaxed); // write rows RETURN_IF_ERROR(_file_writer->append({row_binary, offset})); _count++; diff --git a/be/src/olap/wal_writer.h b/be/src/olap/wal_writer.h index 12fd84f258fb7d..9fd0a396788fc5 100644 --- a/be/src/olap/wal_writer.h +++ b/be/src/olap/wal_writer.h @@ -17,9 +17,13 @@ #pragma once +#include +#include + #include "common/status.h" #include "gen_cpp/internal_service.pb.h" #include "io/fs/file_reader_writer_fwd.h" +#include "util/lock.h" namespace doris { @@ -27,23 +31,30 @@ using PBlockArray = std::vector; class WalWriter { public: - explicit WalWriter(const std::string& file_name); + explicit WalWriter(const std::string& file_name, + const std::shared_ptr& all_wal_disk_bytes); ~WalWriter(); Status init(); Status finalize(); Status append_blocks(const PBlockArray& blocks); + size_t disk_bytes() const { return _disk_bytes; }; std::string file_name() { return _file_name; }; static const int64_t LENGTH_SIZE = 8; static const int64_t CHECKSUM_SIZE = 4; + doris::ConditionVariable cv; private: + static constexpr size_t MAX_WAL_WRITE_WAIT_TIME = 1000; std::string _file_name; io::FileWriterPtr _file_writer; int64_t _count; int64_t _batch; + size_t _disk_bytes; + std::shared_ptr _all_wal_disk_bytes; + doris::Mutex _mutex; }; } // namespace doris \ No newline at end of file diff --git a/be/test/olap/wal_manager_test.cpp b/be/test/olap/wal_manager_test.cpp index fbb5fdbf03fe67..ec387680a635ce 100644 --- a/be/test/olap/wal_manager_test.cpp +++ b/be/test/olap/wal_manager_test.cpp @@ -78,7 +78,9 @@ class WalManagerTest : public testing::Test { void prepare() { static_cast(io::global_local_filesystem()->create_directory(wal_dir)); } void createWal(const std::string& wal_path) { - auto wal_writer = WalWriter(wal_path); + std::shared_ptr _all_wal_disk_bytes = + std::make_shared(0); + auto wal_writer = WalWriter(wal_path, _all_wal_disk_bytes); static_cast(wal_writer.init()); static_cast(wal_writer.finalize()); } diff --git a/be/test/olap/wal_reader_writer_test.cpp b/be/test/olap/wal_reader_writer_test.cpp index 71c822013a2b0d..09460477e38a30 100644 --- a/be/test/olap/wal_reader_writer_test.cpp +++ b/be/test/olap/wal_reader_writer_test.cpp @@ -17,6 +17,7 @@ #include #include +#include #include "agent/be_exec_version_manager.h" #include "common/object_pool.h" @@ -89,7 +90,9 @@ void generate_block(PBlock& pblock, int row_index) { TEST_F(WalReaderWriterTest, TestWriteAndRead1) { std::string file_name = _s_test_data_path + "/abcd123.txt"; - auto wal_writer = WalWriter(file_name); + std::shared_ptr _all_wal_disk_bytes = + std::make_shared(0); + auto wal_writer = WalWriter(file_name, _all_wal_disk_bytes); static_cast(wal_writer.init()); size_t file_len = 0; int64_t file_size = -1; From 22bf2889e5d47175d18942fa02db47d1f6128763 Mon Sep 17 00:00:00 2001 From: wudongliang <46414265+DongLiang-0@users.noreply.github.com> Date: Thu, 9 Nov 2023 13:58:49 +0800 Subject: [PATCH 86/88] [feature](tvf)(jni-avro)jni-avro scanner add complex data types (#26236) Support avro's enum, record, union data types --- .../vec/exec/format/avro/avro_jni_reader.cpp | 44 +++-- .../avro/avro_all_types/all_type.avro | Bin 0 -> 1155 bytes .../apache/doris/avro/AvroColumnValue.java | 34 +++- .../org/apache/doris/avro/AvroJNIScanner.java | 56 +------ .../org/apache/doris/avro/AvroTypeUtils.java | 122 ++++++++++++++ .../apache/doris/avro/AvroTypeUtilsTest.java | 105 ++++++++++++ .../doris/common/jni/vec/TableSchema.java | 10 +- .../external_table_p0/tvf/test_tvf_avro.out | 73 +++++++++ .../tvf/test_tvf_avro.groovy | 154 ++++++++++++++++++ 9 files changed, 513 insertions(+), 85 deletions(-) create mode 100644 docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/avro/avro_all_types/all_type.avro create mode 100644 fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroTypeUtils.java create mode 100644 fe/be-java-extensions/avro-scanner/src/test/java/org/apache/doris/avro/AvroTypeUtilsTest.java create mode 100644 regression-test/data/external_table_p0/tvf/test_tvf_avro.out create mode 100644 regression-test/suites/external_table_p0/tvf/test_tvf_avro.groovy diff --git a/be/src/vec/exec/format/avro/avro_jni_reader.cpp b/be/src/vec/exec/format/avro/avro_jni_reader.cpp index e682ff9886d644..f3cff19c04d9be 100644 --- a/be/src/vec/exec/format/avro/avro_jni_reader.cpp +++ b/be/src/vec/exec/format/avro/avro_jni_reader.cpp @@ -86,18 +86,10 @@ Status AvroJNIReader::init_fetch_table_reader( {"file_type", std::to_string(type)}, {"is_get_table_schema", "false"}, {"hive.serde", "org.apache.hadoop.hive.serde2.avro.AvroSerDe"}}; - switch (type) { - case TFileType::FILE_HDFS: - required_param.insert(std::make_pair("uri", _params.hdfs_params.hdfs_conf.data()->value)); - break; - case TFileType::FILE_S3: - required_param.insert(std::make_pair("uri", _range.path)); + if (type == TFileType::FILE_S3) { required_param.insert(_params.properties.begin(), _params.properties.end()); - break; - default: - return Status::InternalError("unsupported file reader type: {}", std::to_string(type)); } - required_param.insert(_params.properties.begin(), _params.properties.end()); + required_param.insert(std::make_pair("uri", _range.path)); _jni_connector = std::make_unique("org/apache/doris/avro/AvroJNIScanner", required_param, column_names); RETURN_IF_ERROR(_jni_connector->init(_colname_to_value_range)); @@ -144,8 +136,7 @@ Status AvroJNIReader::get_parsed_schema(std::vector* col_names, } TypeDescriptor AvroJNIReader::convert_to_doris_type(const rapidjson::Value& column_schema) { - ::doris::TPrimitiveType::type schema_type = - static_cast< ::doris::TPrimitiveType::type>(column_schema["type"].GetInt()); + auto schema_type = static_cast< ::doris::TPrimitiveType::type>(column_schema["type"].GetInt()); switch (schema_type) { case TPrimitiveType::INT: case TPrimitiveType::STRING: @@ -153,30 +144,35 @@ TypeDescriptor AvroJNIReader::convert_to_doris_type(const rapidjson::Value& colu case TPrimitiveType::BOOLEAN: case TPrimitiveType::DOUBLE: case TPrimitiveType::FLOAT: - return TypeDescriptor(thrift_to_type(schema_type)); + case TPrimitiveType::BINARY: + return {thrift_to_type(schema_type)}; case TPrimitiveType::ARRAY: { TypeDescriptor list_type(PrimitiveType::TYPE_ARRAY); - list_type.add_sub_type(convert_complex_type(column_schema["childColumn"].GetObject())); + const rapidjson::Value& childColumns = column_schema["childColumns"]; + list_type.add_sub_type(convert_to_doris_type(childColumns[0])); return list_type; } case TPrimitiveType::MAP: { TypeDescriptor map_type(PrimitiveType::TYPE_MAP); - + const rapidjson::Value& childColumns = column_schema["childColumns"]; // The default type of AVRO MAP structure key is STRING map_type.add_sub_type(PrimitiveType::TYPE_STRING); - map_type.add_sub_type(convert_complex_type(column_schema["childColumn"].GetObject())); + map_type.add_sub_type(convert_to_doris_type(childColumns[1])); return map_type; } + case TPrimitiveType::STRUCT: { + TypeDescriptor struct_type(PrimitiveType::TYPE_STRUCT); + const rapidjson::Value& childColumns = column_schema["childColumns"]; + for (auto i = 0; i < childColumns.Size(); i++) { + const rapidjson::Value& child = childColumns[i]; + struct_type.add_sub_type(convert_to_doris_type(childColumns[i]), + std::string(child["name"].GetString())); + } + return struct_type; + } default: - return TypeDescriptor(PrimitiveType::INVALID_TYPE); + return {PrimitiveType::INVALID_TYPE}; } } -TypeDescriptor AvroJNIReader::convert_complex_type( - const rapidjson::Document::ConstObject child_schema) { - ::doris::TPrimitiveType::type child_schema_type = - static_cast< ::doris::TPrimitiveType::type>(child_schema["type"].GetInt()); - return TypeDescriptor(thrift_to_type(child_schema_type)); -} - } // namespace doris::vectorized diff --git a/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/avro/avro_all_types/all_type.avro b/docker/thirdparties/docker-compose/hive/scripts/preinstalled_data/avro/avro_all_types/all_type.avro new file mode 100644 index 0000000000000000000000000000000000000000..c66017bb6243ee860863a938a7c08965f121c205 GIT binary patch literal 1155 zcma)5O^ee&7@i43?3P_YkRp4~I3jq6LV|)6glt`x6%|=qPfHJzcIsv`NlHEz!jhwU z6;HCr{sxbNM`7^~c=Q)|^5DsfGm|u#v@3XM>GOWg^FGhp=k6iYdgLgM?j(}~8jv>| z$2iUB6!&pVCs91bCJsp;Fky^?nMc_)!TtT?IzEUZMoGw%Ri|483bQGC9Hvcy$AOxB z8ilW#EE7mg@34p{-7^W*g6$}C8Eqy^ORSa*)7VoVNlL7igj;b;@_I@w1gXMaN&~(* zmh9EWXJo$G70BQbVHrKQDSQ-W!D<^Vqm|}CE~-Yt5ECbP;6_YnkGD7+@Xtd$E>tEj z7M_(()GI7|nRvmR(YpE^Q)_1Bx{Z@=lUbE{(j*rGw+X%sy{NgAeH>=;s;c6#iKlc% zGM3`L$SA9EIi)?VQ>piBi(QA8ohvV^rI_%R`?q|<{~A%p+b`n!)bVLP0CX?i z-X8tAzUJH=O1q5GFJmZA*VqyNM1YWQ>1Xg0Jb?iDHoANZ0Hj@!oAbS%@PPodunhqK z-{9#-_@H~i`M!35*?sKvN+Ob!-d(>a2Ww&?(Eg8z?pv0A0(%3X`}TrJR}ioupTU3F JHh+0po4=>nXx{(; literal 0 HcmV?d00001 diff --git a/fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroColumnValue.java b/fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroColumnValue.java index dd72c9aad5010d..77c6fba37dc679 100644 --- a/fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroColumnValue.java +++ b/fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroColumnValue.java @@ -19,17 +19,25 @@ import org.apache.doris.common.jni.vec.ColumnValue; +import org.apache.avro.generic.GenericData; +import org.apache.avro.generic.GenericData.Fixed; +import org.apache.avro.generic.GenericFixed; +import org.apache.avro.generic.GenericRecord; import org.apache.hadoop.hive.serde2.objectinspector.ListObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.MapObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; import org.apache.hadoop.hive.serde2.objectinspector.PrimitiveObjectInspector; +import org.apache.hadoop.hive.serde2.objectinspector.StructField; +import org.apache.hadoop.hive.serde2.objectinspector.StructObjectInspector; import java.math.BigDecimal; import java.math.BigInteger; +import java.nio.ByteBuffer; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; import java.util.Map.Entry; +import java.util.Objects; public class AvroColumnValue implements ColumnValue { @@ -42,6 +50,12 @@ public AvroColumnValue(ObjectInspector fieldInspector, Object fieldData) { } private Object inspectObject() { + if (fieldData instanceof ByteBuffer) { + return ((PrimitiveObjectInspector) fieldInspector).getPrimitiveJavaObject(((ByteBuffer) fieldData).array()); + } else if (fieldData instanceof Fixed) { + return ((PrimitiveObjectInspector) fieldInspector).getPrimitiveJavaObject( + ((GenericFixed) fieldData).bytes()); + } return ((PrimitiveObjectInspector) fieldInspector).getPrimitiveJavaObject(fieldData); } @@ -162,6 +176,24 @@ public void unpackMap(List keys, List values) { @Override public void unpackStruct(List structFieldIndex, List values) { - + StructObjectInspector inspector = (StructObjectInspector) fieldInspector; + List fields = inspector.getAllStructFieldRefs(); + for (Integer idx : structFieldIndex) { + AvroColumnValue cv = null; + if (idx != null) { + StructField sf = fields.get(idx); + Object o; + if (fieldData instanceof GenericData.Record) { + GenericRecord record = (GenericRecord) inspector.getStructFieldData(fieldData, sf); + o = record.get(idx); + } else { + o = inspector.getStructFieldData(fieldData, sf); + } + if (Objects.nonNull(o)) { + cv = new AvroColumnValue(sf.getFieldObjectInspector(), o); + } + } + values.add(cv); + } } } diff --git a/fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroJNIScanner.java b/fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroJNIScanner.java index 11bce610d70e7a..75cbc721e3142b 100644 --- a/fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroJNIScanner.java +++ b/fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroJNIScanner.java @@ -21,12 +21,9 @@ import org.apache.doris.common.jni.vec.ColumnType; import org.apache.doris.common.jni.vec.ScanPredicate; import org.apache.doris.common.jni.vec.TableSchema; -import org.apache.doris.common.jni.vec.TableSchema.SchemaColumn; import org.apache.doris.thrift.TFileType; -import org.apache.doris.thrift.TPrimitiveType; import org.apache.avro.Schema; -import org.apache.avro.Schema.Field; import org.apache.avro.generic.GenericRecord; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hive.common.JavaUtils; @@ -40,10 +37,7 @@ import org.apache.log4j.Logger; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.Properties; @@ -193,54 +187,6 @@ protected int getNext() throws IOException { @Override protected TableSchema parseTableSchema() throws UnsupportedOperationException { Schema schema = avroReader.getSchema(); - List schemaFields = schema.getFields(); - List schemaColumns = new ArrayList<>(); - for (Field schemaField : schemaFields) { - Schema avroSchema = schemaField.schema(); - String columnName = schemaField.name().toLowerCase(Locale.ROOT); - - SchemaColumn schemaColumn = new SchemaColumn(); - TPrimitiveType tPrimitiveType = serializeSchemaType(avroSchema, schemaColumn); - schemaColumn.setName(columnName); - schemaColumn.setType(tPrimitiveType); - schemaColumns.add(schemaColumn); - } - return new TableSchema(schemaColumns); - } - - private TPrimitiveType serializeSchemaType(Schema avroSchema, SchemaColumn schemaColumn) - throws UnsupportedOperationException { - Schema.Type type = avroSchema.getType(); - switch (type) { - case NULL: - return TPrimitiveType.NULL_TYPE; - case STRING: - return TPrimitiveType.STRING; - case INT: - return TPrimitiveType.INT; - case BOOLEAN: - return TPrimitiveType.BOOLEAN; - case LONG: - return TPrimitiveType.BIGINT; - case FLOAT: - return TPrimitiveType.FLOAT; - case BYTES: - return TPrimitiveType.BINARY; - case DOUBLE: - return TPrimitiveType.DOUBLE; - case ARRAY: - SchemaColumn arrayChildColumn = new SchemaColumn(); - schemaColumn.addChildColumn(arrayChildColumn); - arrayChildColumn.setType(serializeSchemaType(avroSchema.getElementType(), arrayChildColumn)); - return TPrimitiveType.ARRAY; - case MAP: - SchemaColumn mapChildColumn = new SchemaColumn(); - schemaColumn.addChildColumn(mapChildColumn); - mapChildColumn.setType(serializeSchemaType(avroSchema.getValueType(), mapChildColumn)); - return TPrimitiveType.MAP; - default: - throw new UnsupportedOperationException("avro format: " + type.getName() + " is not supported."); - } + return AvroTypeUtils.parseTableSchema(schema); } - } diff --git a/fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroTypeUtils.java b/fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroTypeUtils.java new file mode 100644 index 00000000000000..cd597fa4cfc314 --- /dev/null +++ b/fe/be-java-extensions/avro-scanner/src/main/java/org/apache/doris/avro/AvroTypeUtils.java @@ -0,0 +1,122 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.avro; + +import org.apache.doris.common.jni.vec.TableSchema; +import org.apache.doris.common.jni.vec.TableSchema.SchemaColumn; +import org.apache.doris.thrift.TPrimitiveType; + +import com.google.common.base.Preconditions; +import org.apache.avro.Schema; +import org.apache.avro.Schema.Field; +import org.apache.commons.compress.utils.Lists; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; + +public class AvroTypeUtils { + + protected static TableSchema parseTableSchema(Schema schema) throws UnsupportedOperationException { + List schemaFields = schema.getFields(); + List schemaColumns = new ArrayList<>(); + for (Field schemaField : schemaFields) { + Schema avroSchema = schemaField.schema(); + String columnName = schemaField.name(); + + SchemaColumn schemaColumn = new SchemaColumn(); + TPrimitiveType tPrimitiveType = typeFromAvro(avroSchema, schemaColumn); + schemaColumn.setName(columnName); + schemaColumn.setType(tPrimitiveType); + schemaColumns.add(schemaColumn); + } + return new TableSchema(schemaColumns); + } + + private static TPrimitiveType typeFromAvro(Schema avroSchema, SchemaColumn schemaColumn) + throws UnsupportedOperationException { + Schema.Type type = avroSchema.getType(); + switch (type) { + case ENUM: + case STRING: + return TPrimitiveType.STRING; + case INT: + return TPrimitiveType.INT; + case BOOLEAN: + return TPrimitiveType.BOOLEAN; + case LONG: + return TPrimitiveType.BIGINT; + case FLOAT: + return TPrimitiveType.FLOAT; + case FIXED: + case BYTES: + return TPrimitiveType.BINARY; + case DOUBLE: + return TPrimitiveType.DOUBLE; + case ARRAY: + SchemaColumn arrayChildColumn = new SchemaColumn(); + schemaColumn.addChildColumns(Collections.singletonList(arrayChildColumn)); + arrayChildColumn.setType(typeFromAvro(avroSchema.getElementType(), arrayChildColumn)); + return TPrimitiveType.ARRAY; + case MAP: + // The default type of AVRO MAP structure key is STRING + SchemaColumn keyChildColumn = new SchemaColumn(); + keyChildColumn.setType(TPrimitiveType.STRING); + SchemaColumn valueChildColumn = new SchemaColumn(); + valueChildColumn.setType(typeFromAvro(avroSchema.getValueType(), valueChildColumn)); + + schemaColumn.addChildColumns(Arrays.asList(keyChildColumn, valueChildColumn)); + return TPrimitiveType.MAP; + case RECORD: + List fields = avroSchema.getFields(); + List childSchemaColumn = Lists.newArrayList(); + for (Field field : fields) { + SchemaColumn structChildColumn = new SchemaColumn(); + structChildColumn.setName(field.name()); + structChildColumn.setType(typeFromAvro(field.schema(), structChildColumn)); + childSchemaColumn.add(structChildColumn); + } + schemaColumn.addChildColumns(childSchemaColumn); + return TPrimitiveType.STRUCT; + case UNION: + List nonNullableMembers = filterNullableUnion(avroSchema); + Preconditions.checkArgument(!nonNullableMembers.isEmpty(), + avroSchema.getName() + "Union child type not all nullAble type"); + List childSchemaColumns = Lists.newArrayList(); + for (Schema nullableMember : nonNullableMembers) { + SchemaColumn childColumn = new SchemaColumn(); + childColumn.setName(nullableMember.getName()); + childColumn.setType(typeFromAvro(nullableMember, childColumn)); + childSchemaColumns.add(childColumn); + } + schemaColumn.addChildColumns(childSchemaColumns); + return TPrimitiveType.STRUCT; + default: + throw new UnsupportedOperationException( + "avro format: " + avroSchema.getName() + type.getName() + " is not supported."); + } + } + + private static List filterNullableUnion(Schema schema) { + Preconditions.checkArgument(schema.isUnion(), "Schema must be union"); + return schema.getTypes().stream().filter(s -> !s.isNullable()).collect(Collectors.toList()); + } + +} diff --git a/fe/be-java-extensions/avro-scanner/src/test/java/org/apache/doris/avro/AvroTypeUtilsTest.java b/fe/be-java-extensions/avro-scanner/src/test/java/org/apache/doris/avro/AvroTypeUtilsTest.java new file mode 100644 index 00000000000000..04f5fd217bf47d --- /dev/null +++ b/fe/be-java-extensions/avro-scanner/src/test/java/org/apache/doris/avro/AvroTypeUtilsTest.java @@ -0,0 +1,105 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.apache.doris.avro; + +import org.apache.doris.common.jni.vec.TableSchema; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.avro.Schema; +import org.apache.avro.SchemaBuilder; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.IOException; + +public class AvroTypeUtilsTest { + private Schema allTypesRecordSchema; + private final ObjectMapper objectMapper = new ObjectMapper(); + private String result; + + @Before + public void setUp() { + result = "[{\"name\":\"aBoolean\",\"type\":2,\"childColumns\":null},{\"name\":\"aInt\",\"type\":5," + + "\"childColumns\":null},{\"name\":\"aLong\",\"type\":6,\"childColumns\":null},{\"name\":\"" + + "aFloat\",\"type\":7,\"childColumns\":null},{\"name\":\"aDouble\",\"type\":8,\"childColumns\"" + + ":null},{\"name\":\"aString\",\"type\":23,\"childColumns\":null},{\"name\":\"aBytes\",\"type\"" + + ":11,\"childColumns\":null},{\"name\":\"aFixed\",\"type\":11,\"childColumns\":null},{\"name\"" + + ":\"anArray\",\"type\":20,\"childColumns\":[{\"name\":null,\"type\":5,\"childColumns\":null}]}" + + ",{\"name\":\"aMap\",\"type\":21,\"childColumns\":[{\"name\":null,\"type\":23,\"childColumns\"" + + ":null},{\"name\":null,\"type\":5,\"childColumns\":null}]},{\"name\":\"anEnum\",\"type\":23" + + ",\"childColumns\":null},{\"name\":\"aRecord\",\"type\":22,\"childColumns\":[{\"name\":\"a\"," + + "\"type\":5,\"childColumns\":null},{\"name\":\"b\",\"type\":8,\"childColumns\":null},{\"name\":" + + "\"c\",\"type\":23,\"childColumns\":null}]},{\"name\":\"aUnion\",\"type\":22,\"childColumns\":" + + "[{\"name\":\"string\",\"type\":23,\"childColumns\":null}]}]\n"; + + Schema simpleEnumSchema = SchemaBuilder.enumeration("myEnumType").symbols("A", "B", "C"); + Schema simpleRecordSchema = SchemaBuilder.record("simpleRecord") + .fields() + .name("a") + .type().intType().noDefault() + .name("b") + .type().doubleType().noDefault() + .name("c") + .type().stringType().noDefault() + .endRecord(); + + allTypesRecordSchema = SchemaBuilder.builder() + .record("all") + .fields() + .name("aBoolean") + .type().booleanType().noDefault() + .name("aInt") + .type().intType().noDefault() + .name("aLong") + .type().longType().noDefault() + .name("aFloat") + .type().floatType().noDefault() + .name("aDouble") + .type().doubleType().noDefault() + .name("aString") + .type().stringType().noDefault() + .name("aBytes") + .type().bytesType().noDefault() + .name("aFixed") + .type().fixed("myFixedType").size(16).noDefault() + .name("anArray") + .type().array().items().intType().noDefault() + .name("aMap") + .type().map().values().intType().noDefault() + .name("anEnum") + .type(simpleEnumSchema).noDefault() + .name("aRecord") + .type(simpleRecordSchema).noDefault() + .name("aUnion") + .type().optional().stringType() + .endRecord(); + } + + @Test + public void testParseTableSchema() throws IOException { + TableSchema tableSchema = AvroTypeUtils.parseTableSchema(allTypesRecordSchema); + String tableSchemaTableSchema = tableSchema.getTableSchema(); + JsonNode tableSchemaTree = objectMapper.readTree(tableSchemaTableSchema); + + JsonNode resultSchemaTree = objectMapper.readTree(result); + Assert.assertEquals(resultSchemaTree, tableSchemaTree); + } + +} diff --git a/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/vec/TableSchema.java b/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/vec/TableSchema.java index 421feb55a3fdd0..9e223d0435f9e7 100644 --- a/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/vec/TableSchema.java +++ b/fe/be-java-extensions/java-common/src/main/java/org/apache/doris/common/jni/vec/TableSchema.java @@ -49,7 +49,7 @@ public String getTableSchema() throws IOException { public static class SchemaColumn { private String name; private int type; - private SchemaColumn childColumn; + private List childColumns; public SchemaColumn() { @@ -59,8 +59,8 @@ public String getName() { return name; } - public SchemaColumn getChildColumn() { - return childColumn; + public List getChildColumns() { + return childColumns; } public int getType() { @@ -75,8 +75,8 @@ public void setType(TPrimitiveType type) { this.type = type.getValue(); } - public void addChildColumn(SchemaColumn childColumn) { - this.childColumn = childColumn; + public void addChildColumns(List childColumns) { + this.childColumns = childColumns; } } diff --git a/regression-test/data/external_table_p0/tvf/test_tvf_avro.out b/regression-test/data/external_table_p0/tvf/test_tvf_avro.out new file mode 100644 index 00000000000000..8f39bd410c9e67 --- /dev/null +++ b/regression-test/data/external_table_p0/tvf/test_tvf_avro.out @@ -0,0 +1,73 @@ +-- This file is automatically generated. You should know what you did if you want to edit this +-- !1 -- +aBoolean BOOLEAN Yes false \N NONE +aInt INT Yes false \N NONE +aLong BIGINT Yes false \N NONE +aFloat FLOAT Yes false \N NONE +aDouble DOUBLE Yes false \N NONE +aString TEXT Yes false \N NONE +anArray ARRAY Yes false \N NONE +aMap MAP Yes false \N NONE +anEnum TEXT Yes false \N NONE +aRecord STRUCT Yes false \N NONE +aUnion STRUCT Yes false \N NONE +mapArrayLong MAP> Yes false \N NONE +arrayMapBoolean ARRAY> Yes false \N NONE + +-- !2 -- +2 + +-- !1 -- +false 100 9999 2.11 9.1102 string test [5, 6, 7] {"k1":1, "k2":2} B {"a": 5, "b": 3.14159265358979, "c": "Simple Record String Field"} \N {"k11":[77, 11, 33], "k22":[10, 20]} [{"Key11":1}, {"Key22":0}] +true 42 3400 3.14 9.81 a test string [1, 2, 3, 4] {"key1":1, "key2":2} A {"a": 5, "b": 3.14159265358979, "c": "Simple Record String Field"} \N {"k1":[99, 88, 77], "k2":[10, 20]} [{"arrayMapKey1":0}, {"arrayMapKey2":1}] + +-- !2 -- +[1, 2, 3, 4] +[5, 6, 7] + +-- !3 -- +{"k1":1, "k2":2} +{"key1":1, "key2":2} + +-- !4 -- +A +B + +-- !5 -- +{"a": 5, "b": 3.14159265358979, "c": "Simple Record String Field"} +{"a": 5, "b": 3.14159265358979, "c": "Simple Record String Field"} + +-- !6 -- +\N +\N + +-- !7 -- +{"k1":[99, 88, 77], "k2":[10, 20]} +{"k11":[77, 11, 33], "k22":[10, 20]} + +-- !8 -- +[{"Key11":1}, {"Key22":0}] +[{"arrayMapKey1":0}, {"arrayMapKey2":1}] + +-- !3 -- +aBoolean BOOLEAN Yes false \N NONE +aInt INT Yes false \N NONE +aLong BIGINT Yes false \N NONE +aFloat FLOAT Yes false \N NONE +aDouble DOUBLE Yes false \N NONE +aString TEXT Yes false \N NONE +anArray ARRAY Yes false \N NONE +aMap MAP Yes false \N NONE +anEnum TEXT Yes false \N NONE +aRecord STRUCT Yes false \N NONE +aUnion STRUCT Yes false \N NONE +mapArrayLong MAP> Yes false \N NONE +arrayMapBoolean ARRAY> Yes false \N NONE + +-- !9 -- +false 100 9999 2.11 9.1102 string test [5, 6, 7] {"k1":1, "k2":2} B {"a": 5, "b": 3.14159265358979, "c": "Simple Record String Field"} \N {"k11":[77, 11, 33], "k22":[10, 20]} [{"Key11":1}, {"Key22":0}] +true 42 3400 3.14 9.81 a test string [1, 2, 3, 4] {"key1":1, "key2":2} A {"a": 5, "b": 3.14159265358979, "c": "Simple Record String Field"} \N {"k1":[99, 88, 77], "k2":[10, 20]} [{"arrayMapKey1":0}, {"arrayMapKey2":1}] + +-- !4 -- +2 + diff --git a/regression-test/suites/external_table_p0/tvf/test_tvf_avro.groovy b/regression-test/suites/external_table_p0/tvf/test_tvf_avro.groovy new file mode 100644 index 00000000000000..6f9b4f98b49c42 --- /dev/null +++ b/regression-test/suites/external_table_p0/tvf/test_tvf_avro.groovy @@ -0,0 +1,154 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +suite("test_tvf_avro", "external,hive,tvf,avro,external_docker") { + + def all_type_file = "all_type.avro"; + def format = "avro" + + // s3 config + String ak = getS3AK() + String sk = getS3SK() + String s3_endpoint = getS3Endpoint() + String region = getS3Region() + String bucket = context.config.otherConfigs.get("s3BucketName"); + def s3Uri = "https://${bucket}.${s3_endpoint}/regression/datalake/pipeline_data/tvf/${all_type_file}"; + + // hdfs config + String hdfs_port = context.config.otherConfigs.get("hdfs_port") + String externalEnvIp = context.config.otherConfigs.get("externalEnvIp") + def hdfsUserName = "doris" + def defaultFS = "hdfs://${externalEnvIp}:${hdfs_port}" + def hdfsUri = "${defaultFS}" + "/user/doris/preinstalled_data/avro/avro_all_types/${all_type_file}" + + // TVF s3() + qt_1 """ + desc function s3( + "uri" = "${s3Uri}", + "ACCESS_KEY" = "${ak}", + "SECRET_KEY" = "${sk}", + "REGION" = "${region}", + "FORMAT" = "${format}"); + """ + + qt_2 """ + select count(*) from s3( + "uri" ="${s3Uri}", + "ACCESS_KEY" = "${ak}", + "SECRET_KEY" = "${sk}", + "REGION" = "${region}", + "FORMAT" = "${format}"); + """ + + order_qt_1 """ + select * from s3( + "uri" = "${s3Uri}", + "ACCESS_KEY" = "${ak}", + "SECRET_KEY" = "${sk}", + "REGION" = "${region}", + "FORMAT" = "${format}"); + """ + + order_qt_2 """ + select anArray from s3( + "uri" = "${s3Uri}", + "ACCESS_KEY" = "${ak}", + "SECRET_KEY" = "${sk}", + "REGION" = "${region}", + "FORMAT" = "${format}"); + """ + + order_qt_3 """ + select aMap from s3( + "uri" = "${s3Uri}", + "ACCESS_KEY" = "${ak}", + "SECRET_KEY" = "${sk}", + "REGION" = "${region}", + "FORMAT" = "${format}"); + """ + + order_qt_4 """ + select anEnum from s3( + "uri" = "${s3Uri}", + "ACCESS_KEY" = "${ak}", + "SECRET_KEY" = "${sk}", + "REGION" = "${region}", + "FORMAT" = "${format}"); + """ + + order_qt_5 """ + select aRecord from s3( + "uri" = "${s3Uri}", + "ACCESS_KEY" = "${ak}", + "SECRET_KEY" = "${sk}", + "REGION" = "${region}", + "FORMAT" = "${format}"); + """ + + order_qt_6 """ + select aUnion from s3( + "uri" = "${s3Uri}", + "ACCESS_KEY" = "${ak}", + "SECRET_KEY" = "${sk}", + "REGION" = "${region}", + "FORMAT" = "${format}"); + """ + + order_qt_7 """ + select mapArrayLong from s3( + "uri" ="${s3Uri}", + "ACCESS_KEY" = "${ak}", + "SECRET_KEY" = "${sk}", + "REGION" = "${region}", + "FORMAT" = "${format}"); + """ + + order_qt_8 """ + select arrayMapBoolean from s3( + "uri" = "${s3Uri}", + "ACCESS_KEY" = "${ak}", + "SECRET_KEY" = "${sk}", + "REGION" = "${region}", + "FORMAT" = "${format}"); + """ + + // TVF hdfs() + String enabled = context.config.otherConfigs.get("enableHiveTest") + if (enabled != null && enabled.equalsIgnoreCase("true")) { + try { + qt_3 """ + desc function HDFS( + "uri" = "${hdfsUri}", + "fs.defaultFS" = "${defaultFS}", + "hadoop.username" = "${hdfsUserName}", + "FORMAT" = "${format}"); """ + + order_qt_9 """ select * from HDFS( + "uri" = "${hdfsUri}", + "fs.defaultFS" = "${defaultFS}", + "hadoop.username" = "${hdfsUserName}", + "format" = "${format}")""" + + qt_4 """ select count(*) from HDFS( + "uri" = "${hdfsUri}", + "fs.defaultFS" = "${defaultFS}", + "hadoop.username" = "${hdfsUserName}", + "format" = "${format}"); """ + } finally { + } + } +} \ No newline at end of file From baae7bf33948d0272a6e1b73cfd6e2181461e37e Mon Sep 17 00:00:00 2001 From: daidai <2017501503@qq.com> Date: Thu, 9 Nov 2023 14:07:12 +0800 Subject: [PATCH 87/88] [fix](information_schema)fix bug that metadata_name_ids error tableid and append information_schema case. (#26238) fix bug that #24059 . Added some information_schema scanner tests. files schema_privileges table_privileges partitions rowsets statistics table_constraints Based on infodb_support_ext_catalog=false, it currently includes tests for all tables under the information_schema database. --- be/src/exec/schema_scanner.cpp | 2 - be/src/exec/schema_scanner.h | 6 +- be/src/exec/schema_scanner/schema_helper.cpp | 9 - be/src/exec/schema_scanner/schema_helper.h | 4 - .../schema_metadata_name_ids_scanner.cpp | 4 +- .../query_p0/system/test_query_sys_tables.out | 164 ++++++++++++++++++ .../system/test_query_sys_tables.groovy | 75 +++++++- 7 files changed, 241 insertions(+), 23 deletions(-) diff --git a/be/src/exec/schema_scanner.cpp b/be/src/exec/schema_scanner.cpp index 9733558284a8fd..8d640341bfb9a6 100644 --- a/be/src/exec/schema_scanner.cpp +++ b/be/src/exec/schema_scanner.cpp @@ -60,8 +60,6 @@ namespace doris { class ObjectPool; -DorisServer* SchemaScanner::_s_doris_server; - SchemaScanner::SchemaScanner(const std::vector& columns) : _is_init(false), _param(nullptr), diff --git a/be/src/exec/schema_scanner.h b/be/src/exec/schema_scanner.h index 2d4e468c592676..ec4bc9e0d3da99 100644 --- a/be/src/exec/schema_scanner.h +++ b/be/src/exec/schema_scanner.h @@ -33,7 +33,7 @@ namespace doris { // forehead declare class, because jni function init in DorisServer. -class DorisServer; + class RuntimeState; class ObjectPool; class TUserIdentity; @@ -101,8 +101,6 @@ class SchemaScanner { static std::unique_ptr create(TSchemaTableType::type type); TSchemaTableType::type type() const { return _schema_table_type; } - static void set_doris_server(DorisServer* doris_server) { _s_doris_server = doris_server; } - protected: Status fill_dest_column_for_range(vectorized::Block* block, size_t pos, const std::vector& datas); @@ -113,8 +111,6 @@ class SchemaScanner { // schema table's column desc std::vector _columns; - static DorisServer* _s_doris_server; - TSchemaTableType::type _schema_table_type; RuntimeProfile::Counter* _get_db_timer = nullptr; diff --git a/be/src/exec/schema_scanner/schema_helper.cpp b/be/src/exec/schema_scanner/schema_helper.cpp index 3184aed4d2e4f5..b1d6900e0f5c2f 100644 --- a/be/src/exec/schema_scanner/schema_helper.cpp +++ b/be/src/exec/schema_scanner/schema_helper.cpp @@ -69,15 +69,6 @@ Status SchemaHelper::list_table_metadata_name_ids(const std::string& ip, const i }); } -Status SchemaHelper::describe_table(const std::string& ip, const int32_t port, - const TDescribeTableParams& request, - TDescribeTableResult* result) { - return ThriftRpcHelper::rpc( - ip, port, [&request, &result](FrontendServiceConnection& client) { - client->describeTable(*result, request); - }); -} - Status SchemaHelper::describe_tables(const std::string& ip, const int32_t port, const TDescribeTablesParams& request, TDescribeTablesResult* result) { diff --git a/be/src/exec/schema_scanner/schema_helper.h b/be/src/exec/schema_scanner/schema_helper.h index 900f963f7893cc..c0143136115bf1 100644 --- a/be/src/exec/schema_scanner/schema_helper.h +++ b/be/src/exec/schema_scanner/schema_helper.h @@ -55,10 +55,6 @@ class SchemaHelper { const doris::TGetTablesParams& request, TListTableMetadataNameIdsResult* result); - static Status describe_table(const std::string& ip, const int32_t port, - const TDescribeTableParams& desc_params, - TDescribeTableResult* desc_result); - static Status describe_tables(const std::string& ip, const int32_t port, const TDescribeTablesParams& desc_params, TDescribeTablesResult* desc_result); diff --git a/be/src/exec/schema_scanner/schema_metadata_name_ids_scanner.cpp b/be/src/exec/schema_scanner/schema_metadata_name_ids_scanner.cpp index e69596ef8fa0a7..ef7b2b69c1e710 100644 --- a/be/src/exec/schema_scanner/schema_metadata_name_ids_scanner.cpp +++ b/be/src/exec/schema_scanner/schema_metadata_name_ids_scanner.cpp @@ -193,13 +193,13 @@ Status SchemaMetadataNameIdsScanner::_fill_block_impl(vectorized::Block* block) RETURN_IF_ERROR(fill_dest_column_for_range(block, 3, null_datas)); } } - // table_id + // table_id { int64_t srcs[table_num]; for (int i = 0; i < table_num; ++i) { if (_table_result.tables[i].__isset.id) { srcs[i] = _table_result.tables[i].id; - datas[i] = &srcs; + datas[i] = srcs + i; } else { datas[i] = nullptr; } diff --git a/regression-test/data/query_p0/system/test_query_sys_tables.out b/regression-test/data/query_p0/system/test_query_sys_tables.out index 9d87b432b4a022..91f54556ae8a35 100644 --- a/regression-test/data/query_p0/system/test_query_sys_tables.out +++ b/regression-test/data/query_p0/system/test_query_sys_tables.out @@ -19,12 +19,175 @@ internal bbb 2 varchar varchar(20) 20 internal ccc 3 int int(11) 10 internal ddd 4 smallint smallint(6) 5 +-- !desc_files -- +FILE_ID BIGINT Yes false \N +FILE_NAME TEXT Yes false \N +FILE_TYPE VARCHAR(256) Yes false \N +TABLESPACE_NAME VARCHAR(256) Yes false \N +TABLE_CATALOG CHAR(16) Yes false \N +TABLE_SCHEMA TEXT Yes false \N +TABLE_NAME TEXT Yes false \N +LOGFILE_GROUP_NAME VARCHAR(256) Yes false \N +LOGFILE_GROUP_NUMBER BIGINT Yes false \N +ENGINE VARCHAR(64) Yes false \N +FULLTEXT_KEYS TEXT Yes false \N +DELETED_ROWS TEXT Yes false \N +UPDATE_COUNT TEXT Yes false \N +FREE_EXTENTS BIGINT Yes false \N +TOTAL_EXTENTS BIGINT Yes false \N +EXTENT_SIZE BIGINT Yes false \N +INITIAL_SIZE BIGINT Yes false \N +MAXIMUM_SIZE BIGINT Yes false \N +AUTOEXTEND_SIZE BIGINT Yes false \N +CREATION_TIME TEXT Yes false \N +LAST_UPDATE_TIME TEXT Yes false \N +LAST_ACCESS_TIME TEXT Yes false \N +RECOVER_TIME TEXT Yes false \N +TRANSACTION_COUNTER TEXT Yes false \N +VERSION BIGINT Yes false \N +ROW_FORMAT VARCHAR(256) Yes false \N +TABLE_ROWS TEXT Yes false \N +AVG_ROW_LENGTH TEXT Yes false \N +DATA_LENGTH TEXT Yes false \N +MAX_DATA_LENGTH TEXT Yes false \N +INDEX_LENGTH TEXT Yes false \N +DATA_FREE BIGINT Yes false \N +CREATE_TIME TEXT Yes false \N +UPDATE_TIME TEXT Yes false \N +CHECK_TIME TEXT Yes false \N +CHECKSUM TEXT Yes false \N +STATUS VARCHAR(256) Yes false \N +EXTRA VARCHAR(256) Yes false \N + +-- !query_files -- + +-- !desc_statistics -- +TABLE_CATALOG VARCHAR(512) Yes false \N +TABLE_SCHEMA VARCHAR(64) Yes false \N +TABLE_NAME VARCHAR(64) Yes false \N +NON_UNIQUE BIGINT Yes false \N +INDEX_SCHEMA VARCHAR(64) Yes false \N +INDEX_NAME VARCHAR(64) Yes false \N +SEQ_IN_INDEX BIGINT Yes false \N +COLUMN_NAME VARCHAR(64) Yes false \N +COLLATION VARCHAR(1) Yes false \N +CARDINALITY BIGINT Yes false \N +SUB_PART BIGINT Yes false \N +PACKED VARCHAR(10) Yes false \N +NULLABLE VARCHAR(3) Yes false \N +INDEX_TYPE VARCHAR(16) Yes false \N +COMMENT VARCHAR(16) Yes false \N +INDEX_COMMENT VARCHAR(1024) Yes false \N + +-- !query_statistics -- + +-- !desc_statistics -- +CONSTRAINT_CATALOG VARCHAR(512) Yes false \N +CONSTRAINT_SCHEMA VARCHAR(64) Yes false \N +CONSTRAINT_NAME VARCHAR(64) Yes false \N +TABLE_SCHEMA VARCHAR(64) Yes false \N +TABLE_NAME VARCHAR(64) Yes false \N +CONSTRAINT_TYPE VARCHAR(64) Yes false \N + +-- !query_table_constraints -- + +-- !desc_schema_privileges -- +GRANTEE VARCHAR(81) Yes false \N +TABLE_CATALOG VARCHAR(512) Yes false \N +TABLE_SCHEMA VARCHAR(64) Yes false \N +PRIVILEGE_TYPE VARCHAR(64) Yes false \N +IS_GRANTABLE VARCHAR(3) Yes false \N + +-- !schema_privileges1 -- +'root'@'%' def mysql SELECT NO + +-- !schema_privileges2 -- +'cyw'@'%' def mysql SELECT NO + +-- !schema_privileges3 -- + +-- !desc_table_privileges -- +GRANTEE VARCHAR(81) Yes false \N +TABLE_CATALOG VARCHAR(512) Yes false \N +TABLE_SCHEMA VARCHAR(64) Yes false \N +TABLE_NAME VARCHAR(64) Yes false \N +PRIVILEGE_TYPE VARCHAR(64) Yes false \N +IS_GRANTABLE VARCHAR(3) Yes false \N + +-- !table_privileges -- + +-- !table_privileges2 -- +'cywtable'@'%' def table_privileges_demo test_table_privileges ALTER NO +'cywtable'@'%' def table_privileges_demo test_table_privileges INSERT NO +'cywtable'@'%' def table_privileges_demo test_table_privileges SELECT NO + +-- !table_privileges3 -- +'cywtable'@'%' def table_privileges_demo test_table_privileges ALTER NO +'cywtable'@'%' def table_privileges_demo test_table_privileges INSERT NO + +-- !desc_partitions -- +TABLE_CATALOG VARCHAR(64) Yes false \N +TABLE_SCHEMA VARCHAR(64) Yes false \N +TABLE_NAME VARCHAR(64) Yes false \N +PARTITION_NAME VARCHAR(64) Yes false \N +SUBPARTITION_NAME VARCHAR(64) Yes false \N +PARTITION_ORDINAL_POSITION INT Yes false \N +SUBPARTITION_ORDINAL_POSITION INT Yes false \N +PARTITION_METHOD VARCHAR(13) Yes false \N +SUBPARTITION_METHOD VARCHAR(13) Yes false \N +PARTITION_EXPRESSION VARCHAR(2048) Yes false \N +SUBPARTITION_EXPRESSION VARCHAR(2048) Yes false \N +PARTITION_DESCRIPTION TEXT Yes false \N +TABLE_ROWS BIGINT Yes false \N +AVG_ROW_LENGTH BIGINT Yes false \N +DATA_LENGTH BIGINT Yes false \N +MAX_DATA_LENGTH BIGINT Yes false \N +INDEX_LENGTH BIGINT Yes false \N +DATA_FREE BIGINT Yes false \N +CREATE_TIME BIGINT Yes false \N +UPDATE_TIME DATETIME Yes false \N +CHECK_TIME DATETIME Yes false \N +CHECKSUM BIGINT Yes false \N +PARTITION_COMMENT TEXT Yes false \N +NODEGROUP VARCHAR(256) Yes false \N +TABLESPACE_NAME VARCHAR(268) Yes false \N + +-- !select_partitions -- + +-- !desc_rowsets -- +BACKEND_ID BIGINT Yes false \N +ROWSET_ID VARCHAR(64) Yes false \N +TABLET_ID BIGINT Yes false \N +ROWSET_NUM_ROWS BIGINT Yes false \N +TXN_ID BIGINT Yes false \N +NUM_SEGMENTS BIGINT Yes false \N +START_VERSION BIGINT Yes false \N +END_VERSION BIGINT Yes false \N +INDEX_DISK_SIZE BIGINT Yes false \N +DATA_DISK_SIZE BIGINT Yes false \N +CREATION_TIME BIGINT Yes false \N +NEWEST_WRITE_TIMESTAMP BIGINT Yes false \N + +-- !rowsets1 -- +0 1 + +-- !rowsets2 -- +0 1 +2 2 + +-- !rowsets3 -- +0 1 +2 2 +3 3 +4 4 + -- !schemata -- internal test_query_sys_db_1 \N internal test_query_sys_db_2 \N internal test_query_sys_db_3 \N -- !tables -- +internal test_query_rowset BASE TABLE 0 \N \N internal test_query_sys_tb_1 BASE TABLE 0 \N \N internal test_query_sys_tb_2 BASE TABLE 0 \N \N internal test_query_sys_tb_3 BASE TABLE 0 \N \N @@ -58,3 +221,4 @@ test_view -- !sql -- -- !sql -- + diff --git a/regression-test/suites/query_p0/system/test_query_sys_tables.groovy b/regression-test/suites/query_p0/system/test_query_sys_tables.groovy index baf5d3aa7ea110..ad4a5f12bb1dd5 100644 --- a/regression-test/suites/query_p0/system/test_query_sys_tables.groovy +++ b/regression-test/suites/query_p0/system/test_query_sys_tables.groovy @@ -87,12 +87,85 @@ suite("test_query_sys_tables", "query,p0") { // test files // have no impl + qt_desc_files """desc `information_schema`.`files` """ + order_qt_query_files """ select * from `information_schema`.`files` """ + + //test information_schema.statistics + // have no impl + qt_desc_statistics """desc `information_schema`.`statistics` """ + order_qt_query_statistics """ select * from `information_schema`.`statistics` """ + + //test information_schema.table_constraints + // have no impl + qt_desc_statistics """desc `information_schema`.`table_constraints` """ + order_qt_query_table_constraints """ select * from `information_schema`.`table_constraints` """ + + + // test schema_privileges + sql """ DROP USER if exists 'cyw'; """ + qt_desc_schema_privileges """desc `information_schema`.`schema_privileges` """ + order_qt_schema_privileges1 """ select * from information_schema.schema_privileges where GRANTEE = "'root'@'%'" ; """ + sql """ CREATE USER 'cyw'; """ + order_qt_schema_privileges2 """ select * from information_schema.schema_privileges where GRANTEE = "'cyw'@'%'" ; """ + sql """ DROP USER 'cyw'; """ + order_qt_schema_privileges3 """ select * from information_schema.schema_privileges where GRANTEE = "'cyw'@'%'" ; """ + + + // test table_privileges + sql """ DROP USER if exists 'cywtable'; """ + qt_desc_table_privileges """desc `information_schema`.`table_privileges` """ + order_qt_table_privileges """ select * from information_schema.table_privileges """ + sql """ CREATE USER 'cywtable'; """ + sql """ CREATE DATABASE IF NOT EXISTS table_privileges_demo """ + sql """ create table IF NOT EXISTS table_privileges_demo.test_table_privileges( + a int , + b boolean , + c string ) + DISTRIBUTED BY HASH(`a`) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1", + "disable_auto_compaction" = "true", + "enable_single_replica_compaction"="true" + );""" + + sql """ GRANT SELECT_PRIV,ALTER_PRIV,LOAD_PRIV ON table_privileges_demo.test_table_privileges TO 'cywtable'@'%'; """ + order_qt_table_privileges2 """ select * from information_schema.table_privileges order by PRIVILEGE_TYPE ; """ + sql """ REVOKE SELECT_PRIV ON table_privileges_demo.test_table_privileges FROM 'cywtable'@'%'; """ + order_qt_table_privileges3 """ select * from information_schema.table_privileges order by PRIVILEGE_TYPE ; """ + // test partitions // have no impl + qt_desc_partitions """ desc `information_schema`.`partitions` """ + order_qt_select_partitions """ select * from `information_schema`.`partitions`; """ + // test rowsets - // have no tablet system table, add this later + qt_desc_rowsets """ desc information_schema.rowsets """ + def rowsets_table_name = """ test_query_sys_db_1.test_query_rowset """ + sql """ drop table if exists ${rowsets_table_name} """ + + sql """ + create table ${rowsets_table_name}( + a int , + b boolean , + c string ) + DISTRIBUTED BY HASH(`a`) BUCKETS 1 + PROPERTIES ( + "replication_num" = "1", + "disable_auto_compaction" = "true", + "enable_single_replica_compaction"="true" + ); + """ + + List> rowsets_table_name_tablets = sql """ show tablets from ${rowsets_table_name} """ + order_qt_rowsets1 """ select START_VERSION,END_VERSION from information_schema.rowsets where TABLET_ID=${rowsets_table_name_tablets[0][0]} order by START_VERSION,END_VERSION; """ + sql """ insert into ${rowsets_table_name} values (1,0,"abc"); """ + order_qt_rowsets2 """ select START_VERSION,END_VERSION from information_schema.rowsets where TABLET_ID=${rowsets_table_name_tablets[0][0]} order by START_VERSION,END_VERSION; """ + sql """ insert into ${rowsets_table_name} values (2,1,"hello world"); """ + sql """ insert into ${rowsets_table_name} values (3,0,"dssadasdsafafdf"); """ + order_qt_rowsets3 """ select START_VERSION,END_VERSION from information_schema.rowsets where TABLET_ID=${rowsets_table_name_tablets[0][0]} order by START_VERSION,END_VERSION; """ + // test schemata // create test dbs From 8bb66066626984c17f19171ea945aba099b1c508 Mon Sep 17 00:00:00 2001 From: zfr95 <87513668+zfr9527@users.noreply.github.com> Date: Thu, 9 Nov 2023 14:38:41 +0800 Subject: [PATCH 88/88] [fix](nestedType)fix nested data type to create table (#26506) --- .../plugins_create_table_nested_type.groovy | 117 +++++++++++++----- .../nested_types/create_table.groovy | 3 +- 2 files changed, 87 insertions(+), 33 deletions(-) diff --git a/regression-test/plugins/plugins_create_table_nested_type.groovy b/regression-test/plugins/plugins_create_table_nested_type.groovy index 9c830795875efc..bb4bdde5818a9c 100644 --- a/regression-test/plugins/plugins_create_table_nested_type.groovy +++ b/regression-test/plugins/plugins_create_table_nested_type.groovy @@ -18,75 +18,130 @@ import org.apache.doris.regression.suite.Suite // create table with nested data type, now default complex data include array, map, struct -Suite.metaClass.create_table_with_nested_type = { int maxDepth, String tbName /* param */ -> +Suite.metaClass.create_table_with_nested_type = { int max_depth, def type_arr, String tb_name /* param */ -> Suite suite = delegate as Suite - maxDepth = maxDepth > 9 ? 9 : maxDepth + try { + if (type_arr.size() != max_depth) { + throw new Exception("level not equal type_arr size") + } + } catch (Exception e) { + logger.info(e.message) + return + } + + def cur_depth = type_arr.size() + max_depth = max_depth > 9 ? 9 : max_depth + max_depth = max_depth < 1 ? 1 : max_depth - def dataTypeArr = ["boolean", "tinyint(4)", "smallint(6)", "int(11)", "bigint(20)", "largeint(40)", "float", +// def datatype_arr = ["boolean", "tinyint(4)", "smallint(6)", "int(11)", "bigint(20)", "largeint(40)", "float", +// "double", "decimal(20, 3)", "decimalv3(20, 3)", "date", "datetime", "datev2", "datetimev2(0)", +// "char(15)", "varchar(100)", "text", "hll","bitmap", "QUANTILE_STATE"] + def datatype_arr = ["boolean", "tinyint(4)", "smallint(6)", "int(11)", "bigint(20)", "largeint(40)", "float", "double", "decimal(20, 3)", "decimalv3(20, 3)", "date", "datetime", "datev2", "datetimev2(0)", "char(15)", "varchar(100)", "text"] - def colNameArr = ["c_bool", "c_tinyint", "c_smallint", "c_int", "c_bigint", "c_largeint", "c_float", + def col_name_arr = ["c_bool", "c_tinyint", "c_smallint", "c_int", "c_bigint", "c_largeint", "c_float", "c_double", "c_decimal", "c_decimalv3", "c_date", "c_datetime", "c_datev2", "c_datetimev2", "c_char", "c_varchar", "c_string"] - def complexDataTypeArr = ["array", "map", "struct"] -// def tbName = "test" + def complex_datatype_arr = ["array", "map", "struct"] + def base_struct_scala = "col1:int(11),col2:tinyint(4),col3:smallint(6),col4:boolean,col5:bigint(20),col6:largeint(40)," + + "col7:float,col8:double,col9:decimal(20, 3),col10:decimalv3(20, 3),col11:date,col12:datetime,col13:datev2,col14:datetimev2(0)," + + "col15:char(15),col16:varchar(100),col17:text" + def colCount = 1 - def memo = new String[20] - def r = new Random() def getDataType - getDataType = { dataType, level -> - if (memo[level] != null) { - return memo[level]; - } + getDataType = { i, level -> StringBuilder res = new StringBuilder(); - def data_r = r.nextInt(3); + def data_r = type_arr[cur_depth - level] if (level == 1) { if (data_r == 0) { - res.append(complexDataTypeArr[data_r]+"<"+dataType+">"); + res.append(complex_datatype_arr[data_r]+"<"+ datatype_arr[i] +">"); } else if (data_r == 1) { - res.append(complexDataTypeArr[data_r]+"<"+dataType+"," +dataType+">"); + if (i == 16) { + res.append(complex_datatype_arr[data_r]+"<"+ datatype_arr[i] +"," + datatype_arr[0] +">"); + } else if (i == 17 || i == 18 || i == 19) { + res.append(complex_datatype_arr[data_r]+""); + } else { + res.append(complex_datatype_arr[data_r]+"<"+ datatype_arr[i] +"," + datatype_arr[i+1] +">"); + } } else if (data_r == 2) { - res.append(complexDataTypeArr[data_r]+""); - colCount++; + res.append(complex_datatype_arr[data_r]+"<"+ base_struct_scala +">"); } } else { level--; if (data_r == 0) { - res.append(complexDataTypeArr[data_r]+"<"+getDataType(dataType, level)+">"); + res.append(complex_datatype_arr[data_r]+"<"+getDataType(i, level)+">"); } else if (data_r == 1) { -// String str = getDataType(dataType, level); - res.append(complexDataTypeArr[data_r]+"<"+getDataType(dataType, level)+"," +getDataType(dataType, level)+">") + if (i == 17 || i == 18 || i == 19) { + res.append(complex_datatype_arr[data_r]+""); + } else { + res.append(complex_datatype_arr[data_r]+"<"+datatype_arr[i]+"," +getDataType(i, level)+">") + } + } else if (data_r == 2) { - res.append(complexDataTypeArr[data_r]+""); + res.append(complex_datatype_arr[data_r]+""); colCount++; } } - memo[level] = res.toString() - return memo[level]; + return res.toString() } - def stmt = "CREATE TABLE IF NOT EXISTS " + tbName + "(\n" + + def stmt = "CREATE TABLE IF NOT EXISTS " + tb_name + "(\n" + "`k1` bigint(11) NULL,\n" - String strTmp = "`" + colNameArr[0] + "` " + getDataType(dataTypeArr[0], maxDepth) + " NULL,\n"; - stmt += strTmp - for (int i = 1; i < dataTypeArr.size(); i++) { - String changeDataType = strTmp.replaceAll(colNameArr[0], colNameArr[i]) - changeDataType = changeDataType.replaceAll(dataTypeArr[0], dataTypeArr[i]) - stmt += changeDataType + + for (int i = 0; i < datatype_arr.size(); i++) { + String strTmp = "`" + col_name_arr[i] + "` " + getDataType(i, max_depth) + " NULL,\n"; + stmt += strTmp } + stmt = stmt.substring(0, stmt.length()-2) stmt += ") ENGINE=OLAP\n" + "DUPLICATE KEY(`k1`)\n" + "COMMENT 'OLAP'\n" + "DISTRIBUTED BY HASH(`k1`) BUCKETS 10\n" + "PROPERTIES(\"replication_num\" = \"1\");" - logger.info(stmt) return stmt } logger.info("Added 'create_table_with_nested_type' function to Suite") +Suite.metaClass.get_create_table_with_nested_type { int depth, String tb_name -> + + List> res = new ArrayList<>(); + List track = new ArrayList(); + +// int depth = 1; + + List nums = new ArrayList<>([0, 1, 2]); + + def backtrack + backtrack = { + if (track.size() == depth) { + List copied = new ArrayList<>(track); + res.add(copied); + return; + } + + for (int i = 0; i < nums.size(); i++) { + track.add(nums.get(i)); + backtrack(); + track.remove(track.size() - 1); + } + } + + backtrack(); + for (int i = 0; i < res.size; i++) { + def date_type_str = "" + for (int j = 0; j < res[i].size; j++) { + date_type_str += res[i][j] + " " + } + logger.info(date_type_str) + def result = create_table_with_nested_type(depth, res[i], tb_name) + logger.info(result) + } +} + +logger.info("Added 'get_create_table_with_nested_type' function to Suite") diff --git a/regression-test/suites/datatype_p0/nested_types/create_table.groovy b/regression-test/suites/datatype_p0/nested_types/create_table.groovy index 8fe270cb33f3e3..94a8d3b09a599d 100644 --- a/regression-test/suites/datatype_p0/nested_types/create_table.groovy +++ b/regression-test/suites/datatype_p0/nested_types/create_table.groovy @@ -19,6 +19,5 @@ suite("create_table_with_nested_type") { // register testPlugin function in ${DORIS_HOME}/regression-test/plugins/plugins_create_table_nested_type.groovy // input the nested depth and table name, the output is table schema // run "bash run-regression-test.sh --run -s create_table_with_nested_type" and watch the logger - def result = create_table_with_nested_type(1, "test") - logger.info(result) + get_create_table_with_nested_type(1, "test") }